c++實現簡單http伺服器
阿新 • • 發佈:2019-02-19
http基於tcp協議的應用層協議,說白了就是寫死的自定義協議,程式碼實現了簡單的get請求,開啟服務後,可以通過網站訪問本地資源,適合新手學習的簡單程式碼,有助於理解get和http報文,很簡單
HttpService.h
#ifndef HTTP_SERVICE #define HTTP_SERVICE #include <stdio.h> #include <winsock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") /* WinSock使用的庫函式 */ /* 定義常量 */ #define HTTP_PORT 6080 /* 連線的預設埠 */ #define HTTP_BUF_SIZE 1024 /* 緩衝區的大小 */ #define HTTP_FILENAME_LEN 999 /* 檔名長度 */ #defineHTTP_FILEEXTENSION_LEN 20//檔案字尾長度 #defineHTTP_CMD_LEN 20//命令長度 /* 定義檔案型別對應的 Content-Type */ struct FileExtension { char * pExtensive; /* 檔案字尾 */ char * pType;/* Content-Type */ }; class HttpService { public: char cRecvBuffer[HTTP_BUF_SIZE];//快取請求命令 protected: char cRecvFile[HTTP_FILENAME_LEN];//請求檔案 char cExtensive[HTTP_FILEEXTENSION_LEN];//檔案字尾 char cHttpCmd[HTTP_CMD_LEN]; public: HttpService(); ~HttpService(); public: void AnalyRecvBuffer(); void HttpResponse(SOCKET sSocket); protected: void Cmd_Get(SOCKET sSocket); void Cmd_Post(SOCKET sSocket); char *AnalyExtensive(); }; #endif;
httpService類實現
HttpService.cpp
#include "HttpService.h" char * pHttpHead = "HTTP/1.1 200 OK\r\nDate:%s\r\nServer: ZhaoYueYou's Server \r\n" "Accept-Ranges: bytes\r\nContent-Length: %d\r\nConnection: close\r\n" "Content-Type: %s\r\n\r\n"; struct FileExtension FileType[] = { {"html", "text/html" }, {"gif", "image/gif" }, {"jpeg", "image/jpeg" }, {"jpg", "image/jpeg" }, {"png", "image/png"}, { "js", "text/javascript"}, {"css", "text/css"}, {"txt", "text/plain"}, {"mp4", "video/mp4"}, { NULL, NULL } }; HttpService::HttpService() { memset(cRecvBuffer,0,HTTP_BUF_SIZE); memset(cRecvFile,0,HTTP_FILENAME_LEN); memset(cExtensive,0,HTTP_FILEEXTENSION_LEN); memset(cHttpCmd,0,HTTP_CMD_LEN); } HttpService::~HttpService() { } void HttpService::AnalyRecvBuffer() { int nLength = 0; char *pBegin; char *pEnd; char *pFile; int nHeadLen = 0; /* 查詢 URL 的開始位置 */ pBegin = strchr(cRecvBuffer, ' '); nHeadLen = pBegin-cRecvBuffer; if(nHeadLen<HTTP_CMD_LEN && nHeadLen>0) memcpy(cHttpCmd, cRecvBuffer, nHeadLen); else std::cout<<"命令頭長度異常 "<<std::endl; pBegin += 1; /* 查詢 URL 的結束位置 */ pEnd = strchr(pBegin, ' '); *pEnd = 0; pFile = strchr(pBegin, '/'); nLength = pEnd - pFile; /* 找到檔名的開始位置 */ if ((*pFile == '/') || (*pFile == '\\')) { pFile++; nLength--; } /* 得到檔名 */ if (nLength > 0 && nLength <HTTP_FILENAME_LEN ) { memcpy(cRecvFile, pFile, nLength); cRecvFile[nLength] = 0; pBegin = strchr(cRecvFile, '.'); int nExtensiveLen = pEnd-pBegin; if (pBegin && nExtensiveLen<HTTP_FILEEXTENSION_LEN) strcpy(cExtensive, pBegin + 1); else std::cout<<"字尾長度異常 "<<std::endl; } else std::cout<<"檔案長度異常 "<<std::endl; } void HttpService::HttpResponse(SOCKET sSocket) { if(!strcmp(cHttpCmd,"GET")) Cmd_Get(sSocket); else if(!strcmp(cHttpCmd,"POST")) Cmd_Post(sSocket); else { std::cout<<"其他命令 "<<cHttpCmd<<std::endl; } } void HttpService::Cmd_Get(SOCKET sSocket) { int nHttpHeadLen =0; int nFileLen = 0; int nSendLen = 0; int nRendLen = 0; char cReadBuf[HTTP_FILENAME_LEN] = {0}; FILE *pFile; char *pFileType; pFile = fopen(cRecvFile, "rb+"); /* 用二進位制格式開啟檔案 */ if (pFile == NULL) { printf("[Web] The file [%s] is not existed\n", cRecvFile); return ; } fseek(pFile, 0, SEEK_END); nFileLen = ftell(pFile); fseek(pFile, 0, SEEK_SET); pFileType = AnalyExtensive(); if (pFileType == NULL) { printf("[Web] There is not the related content type\n"); return ; } SYSTEMTIME sys; GetLocalTime( &sys ); char ptr[40]={0}; sprintf( ptr,"%4d/%02d/%02d %02d:%02d:%02d.%03d ",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond,sys.wMilliseconds,sys.wDayOfWeek); /* 構造 HTTP 首部,併發送 */ char HttpHeader[HTTP_FILENAME_LEN]={0}; nHttpHeadLen = sprintf(HttpHeader, pHttpHead,ptr, nFileLen, pFileType); nSendLen = send(sSocket, HttpHeader, nHttpHeadLen, 0); std::cout<<HttpHeader<<std::endl; //send_len=1; if (nSendLen == SOCKET_ERROR) { fclose(pFile); printf("[Web] Fail to send, error = %d\n", WSAGetLastError()); return ; } do /* 傳送檔案, HTTP 的訊息體 */ { nRendLen = fread(cReadBuf, sizeof(char), HTTP_FILENAME_LEN, pFile); if (nRendLen > 0) { nSendLen = send(sSocket, cReadBuf, nRendLen, 0); nFileLen -= nRendLen; } } while ((nRendLen > 0) && (nFileLen > 0)); fclose(pFile); } void HttpService::Cmd_Post(SOCKET sSocket) { } char *HttpService::AnalyExtensive() { struct FileExtension *pType; for (pType = FileType; pType->pExtensive; pType++) { if (strcmp(pType->pExtensive, cExtensive) == 0) return pType->pType; } return NULL; }
入口 main
#include "HttpService.h" void main() { WSADATA wsa_data; SOCKET srv_soc = 0, acpt_soc; /* socket 控制代碼 */ struct sockaddr_in serv_addr; /* 伺服器地址 */ struct sockaddr_in from_addr; /* 客戶端地址 */ unsigned short port = HTTP_PORT; int from_len = sizeof(from_addr); int result = 0,recv_len = 0; WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 資源 */ srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 建立 socket */ if (srv_soc == INVALID_SOCKET) { printf("[Web] socket() Fails, error = %d\n", WSAGetLastError()); system("pause"); return ; } /* 伺服器地址 */ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_pton(AF_INET,"180.173.168.61",&serv_addr.sin_addr.s_addr); result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (result == SOCKET_ERROR) /* 繫結失敗 */ { closesocket(srv_soc); perror("bind:"); printf("[Web] Fail to bind, error = %d\n", WSAGetLastError()); system("pause"); return ; } result = listen(srv_soc, SOMAXCONN); printf("[Web] The server is running ... ...\n"); while (1) { acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len); if (acpt_soc == INVALID_SOCKET) /* 接受失敗 */ { printf("[Web] Fail to accept, error = %d\n", WSAGetLastError()); system("pause"); break; } printf("[Web] Accepted address:[%s], port:[%d]\n", inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port)); HttpService hService; recv_len = recv(acpt_soc, hService.cRecvBuffer, HTTP_BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接收失敗 */ { closesocket(acpt_soc); printf("[Web] Fail to recv, error = %d\n", WSAGetLastError()); system("pause"); break; } hService.cRecvBuffer[recv_len] = 0; hService.AnalyRecvBuffer(); hService.HttpResponse(acpt_soc); closesocket(acpt_soc); } closesocket(srv_soc); WSACleanup(); printf("[Web] The server is stopped.\n"); return ; }