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)关闭发送文件
**/

你可能感兴趣的:(webserver实现伪代码)