bool CHttpProtocol::StartHttpSrv()
{
//...
WSAStartup(wVersionRequested,&wsaData);//啟動Socket命令,version就是版本,wsaData用來接收socket實現細節
m_listenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED)//create Socket
bind(m_listenSocket,(LPSOCKADDR)&sockAddr,sizeof(struct sockaddr))//將套接字和sock地址綁定,sock采用(LPSOCKADDR)數據結構
listen(m_listenSocket,SOMAXCONN);//套接字監聽,為客戶連接創建等待隊列,隊列最大長度是SOMAXCONN = 128
m_pListenThread = AfxBeginThread(ListenThread,this);//創建線程,客戶處理模塊在ListenThread實現,listenthread 是一個函數
//...
}
typedef struct REQUEST
{
SOCKET socket; //請求socket
int nMethod; //請求的使用方法,eg get,post
DWORD dwRecv; //收到的字節數
DWORD dwSend; //發送的字節數
HANDLE hFile; //請求的文件
char szFileNamep[_MAX_PATH]; //文件的相對路徑
char postfix[10]; //存儲請求文件的擴展名
char StatuCodeReason[100]; //頭部的status cod 以及 reason-phrase
void* pHttpProtocol; //指向類CHttpProtocol的指針
hExit //退出
}REQUEST, *PREQUEST;
//線程ListenThread的實現
UINT CHttpProtocol::ListenThread(LPVOID param)
{
CHttpProtocol *pHttpProtocol = (CHttpProtocol *)param;
PREQUEST pReq; //指向request結構的指針
SOCKET socketClient; //客戶機連接的套接字
SOCKADDR_IN sockAddr; //Sock 地址
int nLen; //記錄sockaddr_in的長度
while(1)
{
nLen = sizeof(SOCKADDR_IN);
socketClient = accpet(pHttpProtocol->m_listenSocket,(LPSOCKADDR)&SockAddr,&nLen);//套接字等待連接,返回對應已接受的客戶連接的套接字
pReq = new REQUEST ; //創建 REQUEST 結構傳遞給客戶處理線程
//初始化REQUEST結構
pReq->hExit = pHttpProtocol -> m_hExit;
pReq->Socket = socketClient;
pReq ->hFile = INVALID_HANDLE_VALUE;
pReq->dwRecv = 0;
pReq->dwSend = 0;
pReq->pHttpProtocol = pHttpProtocol;
//創建客戶處理線程,處理request
AfxBeginThread( ClientThread, pReq ); //clientthread 是一個函數,在線面
}
}
/*
*ClientThread 負責分析客戶請求中各個協議參數,對分析結果
*查找資源,生成相響應,發送響應
**/
UNIT CHttpProtocol::ClientThread(LPVOID param)
{
BYTE buf[1024];
PREQUEST pReq = (PREQUEST)PARAM; //pReq表示從客戶端傳來的請求
CHttpProtocol *pHttpProtocol = (CHttpProtocol *)pReq->pHttpProtocol;//獲取pReq的http協議對象
pHttpProtocol->RecvRequest(pReq, buf,sizeof(buf));//接收數據,放入緩存buf中
pHttpProtocol->Analyze(pReq,buf);//分析request信息,判斷請求類型,獲取Request-URI;Request-URI可以獲得鏈接的各部分內容
pHttpProtocol->SendHeader(pReq);//發送200(ok)等響應消息
if(Req->nMethod == METHOD_GET)//本程序只支持GET操作,如果是GET,則向客戶端傳送請求數據
{
pHttpProtocol->SendFile(pReq);//向客戶端傳送請求的數據
}
pHttpProtocol->Disconnect(pReq);//斷開連接
delete pReq;//刪除客戶端的request
return 0;
}
//Analyze函數
int CHttpProtocol::Analyze(PREQUEST pReq, LPBYTE pBuf)
{
//分析接收的信息
char szSeps[]='\n';
char * cpTOKEN;
if(strstr((const char *)pBuf,"..")!=NULL);//防止非法請求,strstr判斷后一個參數是否是前一個參數
{
strcpy(pReq->StatuCodeReason,HTTP_STATUS_BADREQUEST);//返回錯誤狀態碼“400 Bad Requst”
return "1";
}
cpToken = strtok((char *)pBuf,szSeps);//緩存中字符串分解為一組標記串,就是將pBuf分解為szSeps
if(!_stricmp(cpToken,"GET"))//只查找get,因為本server只支持get。_stricmp()不區分大小寫比較兩個字符串,相同返回值為0,查找cpToken里面是否有get
{
pReq->nMethod = METHOD_GET
}
else
{
//返回錯誤狀態碼 501 Not Implemented
strcpy(pReq->StatuCodeReason,HTTP_STATUS_NOTIMPLEMENTED)
return 1;
}
//獲取request-uri
cpToken = strtok(NULL,szSeps);//第二次調用該函數,結果返回分割一句后面的字符串(獲取文件名)
if(cpToken == NULL)
{
//返回錯誤狀態碼"400 Bad Request"
}
strcpy(pReq->szFilename,m_strRootDir);
if(strlen(cpToken)>1)
{
strcat(pReq->szFilename,cpToken);//把文件名添加到路徑結尾處形成完整路徑
}
else
{
strcat(pReq->szFilename,"/index.html");//默認請求為主頁
}
return 0;
}
//SendHeader 函數用于發送響應信息,200(ok)等等,SendFile函數用于發送用戶請求的文件
/*
*【SendHeader函數的重要的函數有:】
*FileExist(pReq) //查找請求的文件,文件不存在則return;
*GetCurrentTime((char*)curTime);//獲取當前時間
*GetFileSize(pReq->hFile,NULL);//獲取文件長度
*GetLastModified(pReq->hFile,(char *)last_modified);//獲取文件last-modified時間
*GetContentType(pReq,(char *)ContentType);//獲取文件的類型
*send(pReq->Socket,Header,strlen(Header),0);//Header包含了響應信息,其中有狀態,時間,server,Content-type,長度和lastmodified
*
*【SendFile函數的重要函數有】
*FileExist(pReq) //查找請求的文件,文件不存在則return;
*在死循環里,fRet = ReadFile(pReq->hFile,buf,sizeof(buf),&dwRead,NULL)從hFile讀到buf中,dwRead用來標記發送是否完成。
*如果fRet為0,則發出錯誤信息HTTP_STATUS_SERVERERROR給pReq->Socket
*如果 dwRead = 0,則返回,即跳出死循環,dwRead用來標記發送是否完成。
*SendBuffer(pReq,buf,dwRead);將客戶端請求的內容buf發送給客戶端
*CloseHandle(pReq->hFile)關閉發送文件
**/
webserver實現偽代碼
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
推薦閱讀更多精彩內容
- 分治法 我們首先先介紹分治法。分治法的思想:將原問題分解為幾個規模較小但類似于原問題的子問題,遞歸地求解這些子問題...
- 分支結構 略 循環結構 求近似的圓周率 C C++ Java Python 求近似的自然對數e C C++ Jav...