c++简单实现http协议服务器和客户端
HTTP(超文本傳輸協(xié)議)是一種客戶端與服務(wù)端的傳輸協(xié)議,最早用于瀏覽器和服務(wù)器之間的通信,后來因?yàn)槠涫褂渺`活、方便等特點(diǎn),廣泛用于客戶端與服務(wù)端的通信。文章將簡(jiǎn)單介紹HTTP協(xié)議,同時(shí)以C++方式分別實(shí)現(xiàn)HTTP GET、POST 請(qǐng)求
HTTP 請(qǐng)求報(bào)文
HTTP請(qǐng)求報(bào)文的一般格式由4部分組成:請(qǐng)求行、請(qǐng)求頭部、空行、請(qǐng)求數(shù)據(jù)。如下圖所示:
?
1.jpg
請(qǐng)求行:包含3部分內(nèi)容:請(qǐng)求方法,URL,協(xié)議版本。形式如:GET /?aaa=1 HTTP/1.1。請(qǐng)求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS等。URL指請(qǐng)求服務(wù)端的地址,可以是相對(duì)地址或域名形式的絕對(duì)地址。協(xié)議版本主要有HTTP/1.1 HTTP/1.0 HTTP/0.9,后面兩種已很少使用了。
請(qǐng)求頭部:以key/value形式成對(duì)表示頭部參數(shù),以英文冒號(hào)分隔。key名稱的約定寫法為Key,Key-Name,自定義key名稱一般以“X-”開頭。如php的聲明“X-Powered-By:PHP/5.5.4-1”
空行:用來標(biāo)識(shí)請(qǐng)求頭部的數(shù)據(jù)已結(jié)束。
請(qǐng)求數(shù)據(jù):可選項(xiàng),這塊內(nèi)容只在POST方式下使用,作為POST的數(shù)據(jù)表示區(qū)域。使用這塊內(nèi)容,要在請(qǐng)求頭部以Content-Length聲明請(qǐng)求數(shù)據(jù)長(zhǎng)度,以Content-Type聲明請(qǐng)求數(shù)據(jù)類型。
HTTP POST請(qǐng)求
HTTP POST方式是把請(qǐng)求參數(shù)放到HTTP請(qǐng)求報(bào)文的請(qǐng)求數(shù)據(jù)中,為了讓例子更容易看懂,僅保留HTTP Post關(guān)鍵參數(shù),你還可以自定義一些參數(shù),比如瀏覽器喜歡用的User-Agent,Accept,Connection等等
?
char *pHttpPost = "POST %s HTTP/1.1\r\n""Host: %s:%d\r\n""Content-Type: application/x-www-form-urlencoded\r\n""Content-Length: %d\r\n\r\n""%s";char* addr = "http://localhost/post.php"; char* host = "127.0.0.1"; int port = 80; char* msg = "aaa=1&bbb=2";char strHttpPost[1024] = {0}; sprintf(strHttpPost, pHttpPost, addr, host, port, strlen(msg), msg);//這里忽略掉了socket連接代碼send(sockClient, strHttpPost, strlen(strHttpPost), 0);HTTP GET請(qǐng)求
HTTP GET方式是把請(qǐng)求參數(shù)放到HTTP請(qǐng)求報(bào)文的請(qǐng)求行URL中,所以請(qǐng)求行就是“GET /?aaa=1&bbb=2 HTTP/1.1\r\n”。URL最大長(zhǎng)度通常瀏覽器取255,這和文件路徑最大長(zhǎng)度有關(guān)。雖然HTTP允許更大長(zhǎng)度,但不建議怎么做,如果太長(zhǎng)了,可以考慮換成POST方式
?
char *pHttpGet = "GET %s?%s HTTP/1.1\r\n""Host: %s:%d\r\n\r\n";char* addr = "http://localhost/get.php"; char* host = "127.0.0.1"; int post = 80; char* msg = "aaa=1&bbb=2";char strHttpGet[1024] = {0}; sprintf(strHttpGet, pHttpGet, addr, msg, host, post);//這里忽略掉了socket連接代碼send(sockClient, strHttpGet, strlen(strHttpGet), 0);實(shí)現(xiàn)的HTTP
?
#include "HttpConnect.h"#ifdef WIN32 #pragma comment(lib,"ws2_32.lib") #endif HttpConnect::HttpConnect() { #ifdef WIN32//此處一定要初始化一下,否則gethostbyname返回一直為空WSADATA wsa = { 0 };WSAStartup(MAKEWORD(2, 2), &wsa); #endif } HttpConnect::~HttpConnect() { } void HttpConnect::socketHttp(std::string host, std::string request) {int sockfd;struct sockaddr_in address;struct hostent *server;sockfd = socket(AF_INET,SOCK_STREAM,0);address.sin_family = AF_INET;address.sin_port = htons(80);server = gethostbyname(host.c_str());memcpy((char *)&address.sin_addr.s_addr,(char*)server->h_addr, server->h_length);if(-1 == connect(sockfd,(struct sockaddr *)&address,sizeof(address))){DBG <<"connection error!"<<std::endl;return;}DBG << request << std::endl; #ifdef WIN32send(sockfd, request.c_str(),request.size(),0); #elsewrite(sockfd,request.c_str(),request.size()); #endifchar buf[1024*1024] = {0};int offset = 0;int rc; #ifdef WIN32while(rc = recv(sockfd, buf+offset, 1024,0)) #elsewhile(rc = read(sockfd, buf+offset, 1024)) #endif{offset += rc;} #ifdef WIN32closesocket(sockfd); #elseclose(sockfd); #endifbuf[offset] = 0;DBG << buf << std::endl; } void HttpConnect::postData(std::string host, std::string path, std::string post_content) {//POST請(qǐng)求方式std::stringstream stream;stream << "POST " << path;stream << " HTTP/1.0\r\n";stream << "Host: "<< host << "\r\n";stream << "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3\r\n";stream << "Content-Type:application/x-www-form-urlencoded\r\n";stream << "Content-Length:" << post_content.length()<<"\r\n";stream << "Connection:close\r\n\r\n";stream << post_content.c_str();socketHttp(host, stream.str()); } void HttpConnect::getData(std::string host, std::string path, std::string get_content) {//GET請(qǐng)求方式std::stringstream stream;stream << "GET " << path << "?" << get_content;stream << " HTTP/1.0\r\n";stream << "Host: " << host << "\r\n";stream <<"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3\r\n";stream <<"Connection:close\r\n\r\n";socketHttp(host, stream.str()); }?
HttpConnect *http = new HttpConnect();http->getData("127.0.0.1", "/login", "id=liukang&pw=123");http->postData("127.0.0.1", "/login","id=liukang&pw=123");
//***********************************
C++實(shí)現(xiàn)簡(jiǎn)單http服務(wù)器
只要懂socket套接字,http請(qǐng)求和響應(yīng)的格式,就行了
#include <winsock2.h>
#include <string>
#include <assert.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define PORT 9999
int main(){
?? ?SOCKET sock;
?? ?SOCKET connfd;
?? ?WORD ver = MAKEWORD(2,2);//版本
?? ?WSADATA dat;
?? ?WSAStartup(ver, &dat);
?? ?sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
?? ?if (sock == -1)
?? ?{
?? ??? ?return false;
?? ?}
?? ?
?? ?struct sockaddr_in sever_address;
?? ?memset(&sever_address,0,sizeof(sever_address));
?? ?sever_address.sin_family = AF_INET;
?? ?sever_address.sin_addr.s_addr =htonl(INADDR_ANY);
?? ?sever_address.sin_port = htons(PORT);
?? ?int ret = bind(sock, (struct sockaddr*)&sever_address,sizeof(sever_address));
?? ?assert(ret != -1);
?? ?ret = listen(sock,10);
?? ?assert(ret != -1);
?? ?cout<<"wait\n";
?? ?while (1)
?? ?{
?? ??? ?struct sockaddr_in client_address;
?? ??? ?int len=sizeof client_address;
?? ??? ?connfd=accept(sock,(sockaddr*)&client_address,&len);
?? ??? ?char buf[1024];
?? ??? ?int n=recv(connfd,buf,sizeof buf,0);
?? ??? ?buf[n]='\0';
?? ??? ?printf("recv:\n%s\n",buf);
?? ??? ?char head[]="HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
?? ??? ?string text1="<!DOCTYPE html>\n<html><head>\n<meta charset=\"gb2312\">\n<title>菜鳥教程(runoob.com)";
?? ??? ?string text2="</title>\n<body>\n<h1>我的第一個(gè)標(biāo)題</h1>\n<p>我的第一個(gè)段落。</p>\n</body>\n</html>
string text=text1+text2;
?? ??? ?
?? ? ? send(connfd,head,strlen(head),0);
?? ? ? send(connfd,text.c_str(),strlen(text.c_str()),0);
?? ? ? printf("send:\n");
?? ? ? cout<<head<<text<<endl;
?? ? ? closesocket(connfd);
?? ?}
? ? closesocket(sock);
?? ?getchar();
}
//********************************
C++ http服務(wù)器和客戶端代碼(無報(bào)文格式)
服務(wù)器代碼
?? ?SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,0);
?? ?int send_len = 0;
?? ?int recv_len = 0;
?? ?//定義服務(wù)端套接字,接受請(qǐng)求套接字
?? ?SOCKET s_server;
?? ?//服務(wù)端地址客戶端地址
?? ?SOCKADDR_IN server_addr;
?? ?//初始化套接字庫(kù)
?? ?WSADATA wsadata;
?? ?WSAStartup(0x22, &wsadata);?? ?
?? ?//填充服務(wù)端地址信息
?? ?//填充服務(wù)端信息
?? ?server_addr.sin_family = AF_INET;
?? ?server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
?? ?server_addr.sin_port = htons(80);
?? ?std::string msgstr="";
?? ?//創(chuàng)建套接字
?? ?s_server = socket(AF_INET, SOCK_STREAM, 0);
?? ?int result = bind(s_server,(struct sockaddr *) &server_addr,sizeof(server_addr));
? ? if (result == SOCKET_ERROR) /* 綁定失敗 */
? ? {
? ? ? ? closesocket(s_server);
? ? ? ? printf("[Web] Fail to bind, error = %d\n", WSAGetLastError());
? ? ? ? return -1;?
? ? }
?? ?if (listen(s_server,SOMAXCONN)==-1) {
?? ??? ?int err = GetLastError();
?? ??? ?std::cout << "服務(wù)器啟動(dòng)失敗!" << std::endl;
?? ??? ?std::cout << err << std::endl;
?? ?}
?? ?else {
?? ??? ?std::cout << "服務(wù)器啟動(dòng)成功!" << std::endl;
?? ?}
?? ?while(1){
?? ??? ?SOCKADDR_IN from_addr; ? /* 客戶端地址 ?*/
?? ??? ?socklen_t from_len = sizeof(from_addr);
?? ??? ?std::string reponse_data="404";
?? ??? ?SOCKET acpt_soc = accept(s_server,(struct sockaddr *) &from_addr,&from_len);
? ? ? ? if (acpt_soc == INVALID_SOCKET) /* 接受失敗 */
? ? ? ? {?? ?int err = GetLastError();
? ? ? ? ? ? printf("接收失敗1", WSAGetLastError());
?? ??? ??? ?std::cout << err << std::endl;
? ? ? ? ? ? break;?
? ? ? ? }
?? ??? ??? ?char recv_buf [1025] = "";
?? ??? ??? ?recv_len = recv(acpt_soc,recv_buf,1025, 0);
?? ??? ??? ?if (recv_len < 0) {
?? ??? ??? ?std::cout << "接收失敗2!" << std::endl;
?? ??? ??? ?}else{
?? ??? ??? ?std::cout << "接收成功!" << std::endl;
?? ??? ??? ?std::cout << recv_buf << std::endl;
?? ??? ??? ?}
?? ??? ??? ?send_len = send(acpt_soc,recv_buf,strlen(recv_buf), 0);
?? ??? ??? ?if (send_len < 0) {
?? ??? ??? ??? ?std::cout << "發(fā)送失敗!" << std::endl;
?? ??? ??? ??? ?closesocket(acpt_soc);
?? ??? ??? ?}else{
?? ??? ??? ??? ?std::cout << "發(fā)送成功!" << std::endl;
?? ??? ??? ?}
?? ?}
?? ?//關(guān)閉套接字
?? ?closesocket(s_server);
?? ?//釋放DLL資源
?? ?WSACleanup();
客戶端代碼
?? ?SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,0);
?? ??? ?//printf("客戶端嵌套字已經(jīng)打開!\n");
?? ?int send_len = 0;
?? ?int recv_len = 0;
?? ?//定義服務(wù)端套接字,接受請(qǐng)求套接字
?? ?SOCKET s_server;
?? ?//服務(wù)端地址客戶端地址
?? ?SOCKADDR_IN server_addr;
?? ?//初始化套接字庫(kù)
?? ?WSADATA wsadata;
?? ?WSAStartup(0x22, &wsadata);?? ?
?? ?//填充服務(wù)端地址信息
?? ?//填充服務(wù)端信息
?? ?server_addr.sin_family = AF_INET;
?? ?server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
?? ?server_addr.sin_port = htons(12580);
?? ?string msgstr="";
?? ?//創(chuàng)建套接字
?? ?s_server = socket(AF_INET, SOCK_STREAM, 0);
?? ?int nTimeout = 120000;
?? ?//設(shè)置接收超時(shí)為1000ms
?? ?if (SOCKET_ERROR == setsockopt(s_server, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int)))
?? ?{
?? ??? ?fprintf(stderr, "Set SO_RCVTIMEO error !\n");
?? ?}
?? ?if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
?? ??? ?cout << "服務(wù)器連接失敗!" << endl;
?? ??? ?closesocket(s_server);
?? ??? ?//釋放DLL資源
?? ??? ?WSACleanup();
?? ??? ?return 0;
?? ?}
?? ?else {
?? ??? ?cout << "服務(wù)器連接成功!" << endl;
?? ?}
?? ?//發(fā)送,接收數(shù)據(jù)
?? ??? ?cout << "開始傳輸桌面信息:"<< endl;
?? ?while(1){
?? ??? ??? ?char send_buf [1025] = "111";
?? ??? ??? ?send_len = send(s_server,send_buf,strlen(send_buf), 0);
?? ??? ??? ??? ?if (send_len < 0) {
?? ??? ??? ??? ??? ?cout << "發(fā)送失敗!" << endl;
?? ??? ??? ??? ??? ?closesocket(s_server);
?? ??? ??? ??? ??? ?//釋放DLL資源
?? ??? ??? ??? ??? ?WSACleanup();
?? ??? ??? ??? ??? ?return 0;
?? ??? ??? ??? ?}else{
?? ??? ??? ??? ??? ?cout << "發(fā)送成功!" << endl;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?char recv_buf [1025] = "";
?? ??? ??? ??? ?recv_len = recv(s_server,recv_buf,1025, 0);
?? ??? ??? ??? ?if (recv_len < 0) {
?? ??? ??? ??? ??? ?cout << "接收失敗!" << endl;
?? ??? ??? ??? ??? ?closesocket(s_server);
?? ??? ??? ??? ??? ?//釋放DLL資源
?? ??? ??? ??? ??? ?WSACleanup();
?? ??? ??? ??? ??? ?return 0;
?? ??? ??? ??? ?}else{
?? ??? ??? ??? ??? ?cout <<recv_buf<< endl;
?? ??? ??? ??? ??? ?cout << "接收成功!" << endl;
?? ??? ??? ??? ?}
?? ?}
?? ?//關(guān)閉套接字
?? ?closesocket(s_server);
?? ?//釋放DLL資源
?? ?WSACleanup();
//************************************
C++實(shí)現(xiàn)簡(jiǎn)單的HTTP服務(wù)器
#include <Winsock2.h> #include <windows.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include <time.h> #pragma comment (lib,"ws2_32") #define uPort 80 #define MAX_BUFFER 100000 #define SENDBLOCK 200000 #define SERVERNAME "AcIDSoftWebServer/0.1b" #define FileName "HelloWorld.html" typedef struct _NODE_ { SOCKET s; sockaddr_in Addr; _NODE_* pNext; }Node,*pNode; //多線程處理多個(gè)客戶端的連接 typedef struct _THREAD_ { DWORD ThreadID; HANDLE hThread; _THREAD_* pNext; }Thread,*pThread; pNode pHead = NULL; pNode pTail = NULL; pThread pHeadThread = NULL; pThread pTailThread = NULL; bool InitSocket();//線程函數(shù) DWORD WINAPI AcceptThread(LPVOID lpParam); DWORD WINAPI ClientThread(LPVOID lpParam); bool IoComplete(char* szRequest); //數(shù)據(jù)包的校驗(yàn)函數(shù) bool AddClientList(SOCKET s,sockaddr_in addr); bool AddThreadList(HANDLE hThread,DWORD ThreadID); bool ParseRequest(char* szRequest, char* szResponse, BOOL &bKeepAlive); //我們存放Html文件的目錄 char HtmlDir[512]={0}; void main() { if (!InitSocket()) { printf("InitSocket Error\n"); return; } GetCurrentDirectory(512,HtmlDir); strcat(HtmlDir,"\\HTML\\"); strcat(HtmlDir,FileName); //啟動(dòng)一個(gè)接受線程 HANDLE hAcceptThread = CreateThread(NULL,0,AcceptThread,NULL,0,NULL); //在這里我們使用事件模型來實(shí)現(xiàn)我們的Web服務(wù)器 //創(chuàng)建一個(gè)事件 WaitForSingleObject(hAcceptThread,INFINITE); } DWORD WINAPI AcceptThread(LPVOID lpParam) //接收線程 { //創(chuàng)建一個(gè)監(jiān)聽套接字 SOCKET sListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); //使用事件重疊的套接字 if (sListen==INVALID_SOCKET) { printf("Create Listen Error\n"); return -1; } //初始化本服務(wù)器的地址 sockaddr_in LocalAddr; LocalAddr.sin_addr.S_un.S_addr = INADDR_ANY; LocalAddr.sin_family = AF_INET; LocalAddr.sin_port = htons(uPort); //綁定套接字 80端口 int Ret = bind(sListen,(sockaddr*)&LocalAddr,sizeof(LocalAddr)); if (Ret==SOCKET_ERROR) { printf("Bind Error\n"); return -1; } //監(jiān)聽 listen(sListen,5); //創(chuàng)建一個(gè)事件 WSAEVENT Event = WSACreateEvent(); if (Event==WSA_INVALID_EVENT) { printf("Create WSAEVENT Error\n"); closesocket(sListen); CloseHandle(Event); //創(chuàng)建事件失敗 關(guān)閉套接字 關(guān)閉事件 return -1; } //將我們的監(jiān)聽套接字與我們的事件進(jìn)行關(guān)聯(lián)屬性為Accept WSAEventSelect(sListen,Event,FD_ACCEPT); WSANETWORKEVENTS NetWorkEvent; sockaddr_in ClientAddr; int nLen = sizeof(ClientAddr); DWORD dwIndex = 0; while (1) { dwIndex = WSAWaitForMultipleEvents(1,&Event,FALSE,WSA_INFINITE,FALSE); dwIndex = dwIndex - WAIT_OBJECT_0; if (dwIndex==WSA_WAIT_TIMEOUT||dwIndex==WSA_WAIT_FAILED) { continue; } //如果有真正的事件我們就進(jìn)行判斷 WSAEnumNetworkEvents(sListen,Event,&NetWorkEvent); ResetEvent(&Event); // if (NetWorkEvent.lNetworkEvents == FD_ACCEPT) { if (NetWorkEvent.iErrorCode[FD_ACCEPT_BIT]==0) { //我們要為新的連接進(jìn)行接受并申請(qǐng)內(nèi)存存入鏈表中 SOCKET sClient = WSAAccept(sListen, (sockaddr*)&ClientAddr, &nLen, NULL, NULL); if (sClient==INVALID_SOCKET) { continue; } else { //如果接收成功我們要把用戶的所有信息存放到鏈表中 if (!AddClientList(sClient,ClientAddr)) { continue; } } } } } return 0; } DWORD WINAPI ClientThread(LPVOID lpParam) { //我們將每個(gè)用戶的信息以參數(shù)的形式傳入到該線程 pNode pTemp = (pNode)lpParam; SOCKET sClient = pTemp->s; //這是通信套接字 WSAEVENT Event = WSACreateEvent(); //該事件是與通信套接字關(guān)聯(lián)以判斷事件的種類 WSANETWORKEVENTS NetWorkEvent; char szRequest[1024]={0}; //請(qǐng)求報(bào)文 char szResponse[1024]={0}; //響應(yīng)報(bào)文 BOOL bKeepAlive = FALSE; //是否持續(xù)連接 if(Event == WSA_INVALID_EVENT) { return -1; } int Ret = WSAEventSelect(sClient, Event, FD_READ | FD_WRITE | FD_CLOSE); //關(guān)聯(lián)事件和套接字 DWORD dwIndex = 0; while (1) { dwIndex = WSAWaitForMultipleEvents(1,&Event,FALSE,WSA_INFINITE,FALSE); dwIndex = dwIndex - WAIT_OBJECT_0; if (dwIndex==WSA_WAIT_TIMEOUT||dwIndex==WSA_WAIT_FAILED) { continue; } // 分析什么網(wǎng)絡(luò)事件產(chǎn)生 Ret = WSAEnumNetworkEvents(sClient,Event,&NetWorkEvent); //其他情況 if(!NetWorkEvent.lNetworkEvents) { continue; } if (NetWorkEvent.lNetworkEvents & FD_READ) //這里很有意思的 { DWORD NumberOfBytesRecvd; WSABUF Buffers; DWORD dwBufferCount = 1; char szBuffer[MAX_BUFFER]; DWORD Flags = 0; Buffers.buf = szBuffer; Buffers.len = MAX_BUFFER; Ret = WSARecv(sClient,&Buffers,dwBufferCount,&NumberOfBytesRecvd,&Flags,NULL,NULL); //我們?cè)谶@里要檢測(cè)是否得到的完整請(qǐng)求 memcpy(szRequest,szBuffer,NumberOfBytesRecvd); if (!IoComplete(szRequest)) //校驗(yàn)數(shù)據(jù)包 { continue; } if (!ParseRequest(szRequest, szResponse, bKeepAlive)) //分析數(shù)據(jù)包 { //我在這里就進(jìn)行了簡(jiǎn)單的處理 continue; } DWORD NumberOfBytesSent = 0; DWORD dwBytesSent = 0; //發(fā)送響應(yīng)到客戶端 do { Buffers.len = (strlen(szResponse) - dwBytesSent) >= SENDBLOCK ? SENDBLOCK : strlen(szResponse) - dwBytesSent; Buffers.buf = (char*)((DWORD)szResponse + dwBytesSent); Ret = WSASend( sClient, &Buffers, 1, &NumberOfBytesSent, 0, 0, NULL); if(SOCKET_ERROR != Ret) dwBytesSent += NumberOfBytesSent; } while((dwBytesSent < strlen(szResponse)) && SOCKET_ERROR != Ret); } if(NetWorkEvent.lNetworkEvents & FD_CLOSE) { //在這里我沒有處理,我們要將內(nèi)存進(jìn)行釋放否則內(nèi)存泄露 } } return 0; } bool InitSocket() { WSADATA wsadata; if (WSAStartup(MAKEWORD(2,2),&wsadata)==0) //使用Socket前必須調(diào)用 參數(shù) 作用 返回值 { return true; } return false; } bool AddClientList(SOCKET s,sockaddr_in addr) { pNode pTemp = (pNode)malloc(sizeof(Node)); HANDLE hThread = NULL; DWORD ThreadID = 0; if (pTemp==NULL) { printf("No Memory\n"); return false; } else { pTemp->s = s; pTemp->Addr = addr; pTemp->pNext = NULL; if (pHead==NULL) { pHead = pTail = pTemp; } else { pTail->pNext = pTemp; pTail = pTail->pNext; } //我們要為用戶開辟新的線程 hThread = CreateThread(NULL,0,ClientThread,(LPVOID)pTemp,0,&ThreadID); if (hThread==NULL) { free(pTemp); return false; } if (!AddThreadList(hThread,ThreadID)) { free(pTemp); return false; } } return true; } bool AddThreadList(HANDLE hThread,DWORD ThreadID) { pThread pTemp = (pThread)malloc(sizeof(Thread)); if (pTemp==NULL) { printf("No Memory\n"); return false; } else { pTemp->hThread = hThread; pTemp->ThreadID = ThreadID; pTemp->pNext = NULL; if (pHeadThread==NULL) { pHeadThread = pTailThread = pTemp; } else { pTailThread->pNext = pTemp; pTailThread = pTailThread->pNext; } } return true; } //校驗(yàn)數(shù)據(jù)包 bool IoComplete(char* szRequest) { char* pTemp = NULL; //定義臨時(shí)空指針 int nLen = strlen(szRequest); //請(qǐng)求數(shù)據(jù)包長(zhǎng)度 pTemp = szRequest; pTemp = pTemp+nLen-4; //定位指針 if (strcmp(pTemp,"\r\n\r\n")==0) //校驗(yàn)請(qǐng)求頭部行末尾的回車控制符和換行符以及空行 { return true; } return false; } //分析數(shù)據(jù)包 bool ParseRequest(char* szRequest, char* szResponse, BOOL &bKeepAlive) { char* p = NULL; p = szRequest; int n = 0; char* pTemp = strstr(p," "); //判斷字符串str2是否是str1的子串。如果是,則該函數(shù)返回str2在str1中首次出現(xiàn)的地址;否則,返回NULL。 n = pTemp - p; //指針長(zhǎng)度 // pTemp = pTemp + n - 1; //將我們的指針下移 //定義一個(gè)臨時(shí)的緩沖區(qū)來存放我們 char szMode[10]={0}; char szFileName[10]={0}; memcpy(szMode,p,n); //將請(qǐng)求方法拷貝到szMode數(shù)組中 if (strcmp(szMode,"GET")==0) //一定要將Get寫成大寫 { //獲取文件名 pTemp = strstr(pTemp," "); pTemp = pTemp + 1; //只有調(diào)試的時(shí)候才能發(fā)現(xiàn)這里的秘密 memcpy(szFileName,pTemp,1); if (strcmp(szFileName,"/")==0) { strcpy(szFileName,FileName); } else { return false; } } else { return false; } // 分析鏈接類型 pTemp = strstr(szRequest,"\nConnection: Keep-Alive"); //協(xié)議版本 n = pTemp - p; if (p>0) { bKeepAlive = TRUE; } else //這里的設(shè)置是為了Proxy程序的運(yùn)行 { bKeepAlive = TRUE; } //定義一個(gè)回顯頭 char pResponseHeader[512]={0}; char szStatusCode[20]={0}; char szContentType[20]={0}; strcpy(szStatusCode,"200 OK"); strcpy(szContentType,"text/html"); char szDT[128]; struct tm *newtime; long ltime; time(<ime); newtime = gmtime(<ime); strftime(szDT, 128,"%a, %d %b %Y %H:%M:%S GMT", newtime); //讀取文件 //定義一個(gè)文件流指針 FILE* fp = fopen(HtmlDir,"rb"); fpos_t lengthActual = 0; int length = 0; char* BufferTemp = NULL; if (fp!=NULL) { // 獲得文件大小 fseek(fp, 0, SEEK_END); fgetpos(fp, &lengthActual); fseek(fp, 0, SEEK_SET); //計(jì)算出文件的大小后我們進(jìn)行分配內(nèi)存 BufferTemp = (char*)malloc(sizeof(char)*((int)lengthActual)); length = fread(BufferTemp,1,(int)lengthActual,fp); fclose(fp); // 返回響應(yīng) sprintf(pResponseHeader, "HTTP/1.0 %s\r\nDate: %s\r\nServer: %s\r\nAccept-Ranges: bytes\r\nContent-Length: %d\r\nConnection: %s\r\nContent-Type: %s\r\n\r\n", szStatusCode, szDT, SERVERNAME, length, bKeepAlive ? "Keep-Alive" : "close", szContentType); //響應(yīng)報(bào)文 } //如果我們的文件沒有找到我們將引導(dǎo)用戶到另外的錯(cuò)誤頁(yè)面 else { } strcpy(szResponse,pResponseHeader); strcat(szResponse,BufferTemp); free(BufferTemp); BufferTemp = NULL; return true; }
總結(jié)
以上是生活随笔為你收集整理的c++简单实现http协议服务器和客户端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ActiveMQ_Windows版本的安
- 下一篇: C/C++ http协议发送字段,文件,