zoukankan      html  css  js  c++  java
  • 基于visual c++之windows核心编程代码分析(32)HTTP协议编程

    超文本传送协议 (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("%s\n",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("%s\n",ServerName); 
               return -1; 
           } 
           memcpy(&pServer->sin_addr,pHost->h_addr_list[0],sizeof(pServer->sin_addr)); 
       } 
        
       return 0; 
    } 


     

  • 相关阅读:
    Hadoop WordCount改进实现正确识别单词以及词频降序排序
    两个栈实现一个队列
    数据库弱一致性四个隔离级别
    vs2008生成lib文件
    开始整理资料
    基于AKS素性检测的素数生成器
    生成指定位数的随机数
    Windows 7远程桌面 重启 关机 任务管理器 命令
    摩根IT实习经验谈及其他
    Hadoop下进行反向索引(Inverted Index)操作
  • 原文地址:https://www.cnblogs.com/new0801/p/6177792.html
Copyright © 2011-2022 走看看