基于visual c++之windows核心编程代码分析(32)HTTP协议编程

本文介绍HTTP协议的基本概念及特点,并通过VC++代码示例展示了如何实现HTTP协议,包括建立连接、处理请求和响应的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

超文本传送协议 (HTTP) 是一种通信协议,它允许将超文本标记语言 (HTML) 文档从 Web 服务器传送到 Web 浏览器。HTML 是一种用于创建文档的标记语言,这些文档包含到相关信息的链接。您可以单击一个链接来访问其它文档、图像或多媒体对象,并获得关于链接项的附加信息。   客户机和服务器必须都支持 HTTP,才能在万维网上发送和接收 HTML 文档并进行交互。  

 HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,特别是在代理服务器中。HTTP/1.1的规范化工作正在进行之中,持久连接被默认采用,并能很好地配合代理服务器工作。而且HTTP-NG(Next Generation of HTTP)的建议已经提出。
  HTTP协议的主要特点可概括如下:

  支持客户/服务器模式。 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

我们来亲自用VC++实现http协议

#include <stdio.h>      
#include <winsock2.h>      
#define  MAXBUFLEN  20480      
#define  HTTPADDLEN 50      
#define  TIMEWAIT   2000      
#pragma comment(lib,"ws2_32.lib")     
SOCKET   Global[1000];      
         
DWORD WINAPI  Proxy( LPVOID pSocket);      
int   ParseHttpRequest(char * SourceBuf,int DataLen,void * ServerAddr);      
         
         
int main(int argc,char * argv[])      
{      
   SOCKET  MainSocket,ClientSocket;      
   struct  sockaddr_in Host,Client;      
   WSADATA WsaData;      
   int  AddLen,i;      
         
   //初始化      
            
   if(WSAStartup(MAKEWORD(2,2),&WsaData) < 0)      
   {      
       printf("初始化失败n");      
       return 1;      
   }      
   //创建socket端口      
   MainSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);      
   if(MainSocket == SOCKET_ERROR)      
   {      
       printf("端口创建错误n");     
       return 1;     
   }      
   Host.sin_family = AF_INET;      
   Host.sin_port = htons(8080);      
   Host.sin_addr.s_addr = inet_addr("127.0.0.1");      
   printf("正在工作n");      
   //绑定socket     
   if(bind(MainSocket,(SOCKADDR *)&Host,sizeof(Host)) != 0)      
   {      
       printf("绑定错误n");     
   }      
   i = 0;      
   //监听      
   if(listen(MainSocket,5) == SOCKET_ERROR)      
   {      
       printf("监听错误n");      
   }      
   AddLen = sizeof(Client);      
         
   //连接新的客户      
   i = 0;      
   for(;;)      
   {      
       ClientSocket = accept(MainSocket,(SOCKADDR *)&Client,&AddLen);      
       if(ClientSocket == SOCKET_ERROR)      
       {      
           printf("接受客户请求错误!n");      
       }      
       printf(".");      
       i ++ ;      
       if( i >= 1000)      
           i = 0;      
       Global[i] = ClientSocket;      
         
       //对于每一个客户启动不同的线程程进行控制      
       //这个地方在使用ClientSocket的时候,要不要保证在某一时刻内只能有一个进程使用?          
         
       CreateThread(NULL,0,Proxy,(LPVOID)Global[i],0,NULL);     
             
                 
   }      
         
             
return 0;     
}      
DWORD WINAPI Proxy( LPVOID pSocket)      
{      
   SOCKET ClientSocket;      
   char  ReceiveBuf[MAXBUFLEN];      
   int  DataLen;      
   struct sockaddr_in  ServerAddr;      
   SOCKET  ProxySocket;      
   int i = 0;      
   int time = TIMEWAIT;      
         
   //得到参数中的端口号信息      
   ClientSocket = (SOCKET)pSocket;      
//接受第一次请求信息      
   memset(ReceiveBuf,0,MAXBUFLEN);      
   DataLen = recv(ClientSocket,ReceiveBuf,MAXBUFLEN,0);      
         
   if(DataLen == SOCKET_ERROR)      
   {      
       printf("错误n");      
       closesocket(ClientSocket);      
      return 0;     
   }      
   if(DataLen == 0)      
   {      
       closesocket(ClientSocket);      
      return 0;     
   }          
   //处理请求信息,分离出服务器地址      
   if( ParseHttpRequest(ReceiveBuf,DataLen,(void *)&ServerAddr) < 0)      
   {      
       closesocket(ClientSocket);      
       goto error;      
   }      
   //创建新的socket用来和服务器进行连接      
   ProxySocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);      
   //设置超时时间      
   setsockopt(ProxySocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&time,sizeof(time));      
   if(ProxySocket == SOCKET_ERROR)      
   {      
       printf("端口创建错误n");      
       return 0;     
   }      
   if(connect(ProxySocket,(SOCKADDR *)&ServerAddr,sizeof(ServerAddr)) == SOCKET_ERROR)      
   {      
       //printf("连接服务器错误");      
       goto error;      
   }      
   //开始进行数据传输处理      
   //发送到服务器端      
   if(send(ProxySocket,ReceiveBuf,DataLen,0) == SOCKET_ERROR)      
   {      
       //printf("数据发送错误");      
       goto error;      
         
   }      
       //从服务器端接受数据      
   while(DataLen > 0)      
   {      
       memset(ReceiveBuf,0,MAXBUFLEN);      
             
       if((DataLen = recv(ProxySocket,ReceiveBuf,MAXBUFLEN,0)) <= 0)      
       {      
           //    printf("数据接受错误");      
           break;      
                     
       }      
       else  
           //发送到客户端      
           if(send(ClientSocket,ReceiveBuf,DataLen,0) < 0)      
           {      
               //    printf("数据发送错误");      
                   break;      
           }      
                 
   }      
             
error:      
   closesocket(ClientSocket);      
   closesocket(ProxySocket);      
         
   return 0;      
         
}      
int  ParseHttpRequest(char * SourceBuf,int DataLen,void * ServerAddr)      
{      
         
   char * HttpHead = "http://";      
   char * FirstLocation = NULL;      
   char * LastLocation = NULL;      
   char * PortLocation = NULL;      
   char  ServerName[HTTPADDLEN];      
   char  PortString[10];      
   int   NameLen;      
   struct hostent * pHost;      
   struct sockaddr_in * pServer = (struct sockaddr_in *)ServerAddr;      
   //取得http://的位置      
   FirstLocation = strstr(SourceBuf,HttpHead) + strlen(HttpHead);      
   //取得/的位置      
   printf("%sn",FirstLocation);     
   LastLocation=strstr(FirstLocation,"/");      
         
   //得到http://和/之间的服务器的名称      
             
   memset(ServerName,0,HTTPADDLEN);      
   memcpy(ServerName,FirstLocation,LastLocation - FirstLocation);      
         
   //有些情况下,请求的地址中带有端口号格式为“:+ 端口号”;      
   //取得 :的位置      
   PortLocation = strstr(ServerName,":");      
         
             
   //填充server结构      
   pServer->sin_family = AF_INET;      
   //在url中制定了服务器端口      
   if(PortLocation != NULL)      
   {      
       NameLen = PortLocation - ServerName -1;      
       memset(PortString,0,10);      
       memcpy(PortString,PortLocation + 1,NameLen);      
       pServer->sin_port = htons((u_short)atoi(PortString));      
       *PortLocation = 0;          
   }      
   else//在url中,没有制定服务器端口      
   {      
       pServer->sin_port=htons(80);      
   }      
         
   if(NameLen > HTTPADDLEN)      
   {      
       printf("服务器名字太长n");      
       return -1;      
   }      
             
   //得到服务器信息      
   //如果地址信息是以IP地址(192.168.0.1)的形式出现的      
   if(ServerName[0] >= '0' && ServerName[0] <= '9')      
   {      
                 
       pServer->sin_addr.s_addr = inet_addr(ServerName);      
   }      
   //以域名的形式出现的(www.sina.com.cn)      
   else  
   {      
       pHost = (struct hostent *)gethostbyname(ServerName);      
       if(!pHost)      
       {      
           printf("取得主机信息错误n");      
           printf("%sn",ServerName);      
           return -1;      
       }      
       memcpy(&pServer->sin_addr,pHost->h_addr_list[0],sizeof(pServer->sin_addr));      
   }      
             
   return 0;      
}

原网址:http://tech.ddvip.com/2012-12/1355234658186903.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值