zoukankan      html  css  js  c++  java
  • 如何利用socket进行HTTP访问(转)

    如何利用socket进行HTTP访问 
    平常我们要访问某个URL一般都是通过浏览器进行:提交一个URL请求后,浏览器将请求发向目标服务器或者代理服务器,目标服务器或者代理服务器返回我们所需要的数据,浏览器接收到这些数据后保存成文件并进行显示。 
    下面我们看看如何自己利用winsock2.h中的接口来实现这个功能?为了简化问题,作以下假设: 

    通过代理服务器进行HTTP访问,这样就省去了对URL进行DNS解析的步骤,假设代理服务器的地址为:192.168.0.1:808。 
      
    这个功能由以下几个部分组成: 
    1. 如何建立连接? 
    2. 如何发送请求? 
    3. 如何接收数据? 
    4. 如何判断数据接收完成? 
      
    下面我们依次来看下这些问题如何解决 

    一、如何建立与服务器之间的连接 

    HTTP基本TCP,所以我们需要与服务器建立连接,然后才能发送数据。 
    建立连接参考如下函数socket_open: 

    01 /*

    02 *打开Socket,返回socketId,-1表示失败

    03 */

    04 int socket_open(int IP,int Port,int type){

    05 SOCKET socketId;

    06  struct sockaddr_in serv_addr;

    07   int status;

    08    

    09  socketId=socket(AF_INET,SOCK_STREAM,0);

    10    

    11  if((int)socketId<0)

    12  {

    13        printf("[ERROR]Create a socket failed!\n");

    14        return -1;

    15  }

    16    

    17  memset(&serv_addr,0,sizeof(serv_addr));

    18  serv_addr.sin_family=AF_INET;

    19  serv_addr.sin_addr.s_addr = ntohl(IP); 

    20  serv_addr.sin_port = htons((USHORT)Port);

    21  status=connect(socketId,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

    22     if(status!=0)

    23  {

    24     printf("[ERROR]Connecting failed!\n"); 

    25     closesocket(socketId);

    26     return -1;

    27  }

    28  return socketId;

    29 }

     
    调用方式如下: 

    1 int socketId=socket_open(0xC0A80001,808,0); //0xC0A80001是192.168.0.1的十六进制写法。


    二、如何发送请求 

    发送数据要根据HTTP协议的要求附加协议头: 

    1 static const char* protocolHead="GET http://www.xxx.com/index.html HTTP/1.1\n"

    2      "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\n"

    3      "Accept-Language: zh-cn\n"

    4      "User-Agent:iPanelBrowser/2.0\n"

    5      "Host: www.xxx.com:80\n"

    6      "Connection: close\n\n"

     
         这里使用GET来获取指定URL的指定文档。 
         建立连接后使用send将这些数据发送出去: 
         send(socketId, protocolHead,strlen(protocolHead),0); 
         发送完成HTTP请求后就等待接收数据。 
            
    三、如何接收数据 

    这里采用select循环查询的方式来判断有无数据到来: 
      

    01 struct timeval tm = {0,7};

    02      fd_set fds_r;

    03      int status;

    04      char recvBuf[4096]={‘\0’};

    05      FD_ZERO(&fds_r);

    06      FD_SET(socketId,&fds_r);

    07        

    08 status=select(socketId+ 1, &fds_r, 0, 0, &tm); //socketId在这里是最大的fd

    09        

    10      if(status > 0 && FD_ISSET(socketId, &fds_r))

    11 {

    12          printf("Socket is readable...fd=[%d]\n",socketId);

    13           recv(socketId,recvBuf,4096,0);

    14 }

     
      
    这样数据包就保存到缓冲区中了。 
      
    四、如何判断数据接收完成 

    首先对返回数据的状态进行判断,仅当状态为“ HTTP 200 OK ”时才表明正确返回,这时才对数据进行解析并保存,如果状态为HTTP 404 NOT FOUND或者其它状态则表明没有找到资源或者出现其它问题,可参考HTTP 1.1状态代码及其含义。 
    当数据正确返回时,为了将实际数据从协议中分离出来进行保存,需要对HTTP数据包进行解析得到Content-Length,然后在包含Content-Length的当前数据包或者随后的数据包中查找第一个空行,这就是内容(Content)的开始位置,再配合前面解析得到的Content-Length,就能够知道什么时候数据接收完成了。换行符为“\r\n”,也兼容“\n”或者“\r”,设换行符为^P,则空行如果位于内容中间或结尾则可查找“^P^P”,若位于开头,则查找^P。 
      
    基本就是上面这些,这四个问题解决了,那么整个问题也就解决了!

  • 相关阅读:
    ID3决策树---Java
    Static、final、abstract、接口、构造方法及java语法总结
    集合类 Collection
    String、StringBuilder
    java基础类:Object类和Math类
    如何快速定位TempDB产生问题
    教你实现图片的惰性加载
    如何在 apache 中开启 gzip 压缩服务
    Data URI 应用场景小结
    获取图片base64编码的几种方法
  • 原文地址:https://www.cnblogs.com/lebronjames/p/1846693.html
Copyright © 2011-2022 走看看