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)关闭发送文件
**/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容