webserver實現偽代碼



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)關閉發送文件
**/
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容