【socket】socket介绍-socket与http服务通信

来源:互联网 发布:js escape 替代 编辑:程序博客网 时间:2024/05/21 22:39

之前几篇文章都是介绍了socket的基础知识,包括socket的TCP/IP协议栈,socket的服务端集中常见的实现模式,还有对于socket在内核中都是如何支持和实现的。这篇文章就讲解socket的一种使用。
在网络通信种,基本所有通信底层的数据传输都是基于socket的。当然可能有部分的应用场景是直接在数据链路层进行传输,跳过TCP/IP协议栈的网络层。不过在绝大多数情况下还有行业中,对于开发者来说网络层就是可见的最低层了。通过socket进行端到端的通信也是最常用的通信方式,可以使用各种各样的协议对要传输的数据进行封装,然后通过socket发送。这篇文章就是讲解使用socket直接访问http服务,通过socket封装http协议,然后进行http的数据通信。

协议介绍

要想直接通过socket来模拟http通信,就必须了解一下几点:
1、TCP是可靠、有序的传输协议。这句话的意思是当接收端接受到网络层的数据的时候,肯定和发送端发送的次序是一致的。你的应用协议层对数据次序是无感的,你不需要对接受到的数据的次序负责,接收到之后就是次序正确的。
2:HTTP是有自己标准的的协议,发送的数据必须符合http标准,对端才能认为这是个正确的http协议。这句话的意思是说socket发送数据是没有所谓的协议的,但是它会封装自己这一层的协议然后扔给数据链路层。对于他发送的数据,它是不管发送的是什么的。然而http是有自己的协议的,我们要通过socket来发送一个http协议的数据给对端的http服务,所以需要你自己封装构造http协议。
对于http协议来说,现在常用的还是http1.0或者http1.1,http2.0标准已经推出,但是普及还需要一定的时间。http协议是一个复杂又庞大的协议,在这里短短的篇幅是无法展开的,只对最需要关注的点进行介绍,之针对http中的get方法进行介绍。
在http通信中最主要的就是http的头部,一个合法的http头决定了这个请求会不会被对端正确解析,并对该条请求提供服务。下面先贴出一个合法的http头部,下面是当你访问百度的时候,它某个请求的http头部。

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding:gzip, deflate, sdchAccept-Language:zh-CN,zh;q=0.8Cache-Control:max-age=0Connection:keep-aliveCookie:BAIDUID=B28CB63662675F1060F6A7343B53C06A:FG=1; BIDUPSID=B28CB63662675F1060F6A7343B53C06A; PSTM=1450582737; BDUSS=pIWXViZnJGOTEzZXcyTWl6eEdNbUwxfmVGWkRiZThvU1lKZDhyNWVOUGdyNTFXQVFBQUFBJCQAAAAAAAAAAAEAAAAW5bsIczEyMDkyMjcxOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAidlbgInZWQ1; BD_HOME=1; H_PS_PSSID=18511_1450_17956_17947_18500_17000_17073_15298_11657_18039_17999; BD_UPN=12314353Host:www.baidu.comUpgrade-Insecure-Requests:1User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36

首先介绍一下http头部属性,然后讲一下为何http头部是非常重要的。对于http头部,每个属性是kv对的形式,通过冒号隔开。每个属性的末尾一个\r\n的换行,而整个http头部结束需要再额外添加一个\r\n。
在这里需要注意的是,对于http协议来说,其不仅仅是包含上面几个属性,也并不是说必须上面几个属性。这个全要看自己的应用特性,可能在平时使用中你所需要的属性比这要少,也可能要多余上面几个属性,只要是合法的http头部,理论上是都可以正常提供服务的。但是在某些特殊的应用个场景下,服务端可能要求客户端必须提供某些属性,必须cache-control,Host等,这就要看具体需求,然后客户端进行具体的修改。
下面就简单介绍一下为何http头部很重要。

协议实现

首先构造http的头部,注意每一个kv对都必须有一个\r\n的结束符,头部的结束还需要额外再添加一个\r\n。的结束符。

    string req = "GET /?req HTTP/1.1\r\n";    req = req + "Accept:text/html,application/xhtml+xml,application/xml\r\n";    req = req  + "Connection:close\r\n";    req = req  + "\r\n";

然后创建socket,准备发送数据

    int port = 10001;    string ip = "127.0.90.1";    struct sockaddr_in server;    int sockfd = socket(AF_INET, SOCK_STREAM, 0);     if(sockfd < 0)    {           perror("create sock failed!!\n");        exit(0);    }       memset(&server, 0, sizeof(server));    server.sin_family = AF_INET;    server.sin_port = htons(port);    server.sin_addr.s_addr = inet_addr(ip.c_str());     if(connect(sockfd, (struct sockaddr*) &server, sizeof(server)) < 0)    {           perror("connect sock failed!!\n");        close(sockfd);        exit(0);    }   

发送数据,在这里通过系统调用write方法,像socket描述符写数据。这里需要注意的是,虽然你告诉了write要发送多少数据,但是它不一定就肯定会把这些数据全部发送出去。所以,你需要记录它这一次调用,发送了多少数据,然后继续对没发送出去的数据调用该方法,直到全部数据发送完。因此你需要一个while循环,还有几个参数来记录全部数据,发送的数据,还有下次从哪个位置发送。

    int bytes = 0, sent = 0, received = 0, total = 0;                                                                                                                                                                          total = req.size();                                                                                                                                                                                                        const char *data = req.c_str();                                                                                                                                                                                            while(sent < total)                                                                                                                                                                                                        {                                                                                                                                                                                                                              bytes = write(sockfd, data + sent, total - sent);                                                                                                                                                                          if(bytes < 0)                                                                                                                                                                                                              {                                                                                                                                                                                                                              perror("send data failed!!\n");                                                                                                                                                                                            close(sockfd);                                                                                                                                                                                                             exit(0);                                                                                                                                                                                                               }                                                                                                                                                                                                                          if(bytes == 0)                                                                                                                                                                                                             {                                                                                                                                                                                                                              break;          }                                                                                                                                                                                                                          sent += bytes;                                                                                                                                                                                                         }                             

等整个请求发送完了,就是要接受服务端返回的数据了。这里同样也需要注意的是和发送的时候一样,当发送数据的时候使用write系统调用,它发送多少数据是不确定的。在接受数据的时候使用read系统调用,它也是如此,虽然你告诉它read多少数据,但是因为网络还有buffer的缘故,它不一定就肯定会read这么多的数据。所以你必须一直不停的读,直到全部数据接受完毕。

    char response[64 * 1024];                                                                                                                                                                                                  while(true)                                                                                                                                                                                                                {                                                                                                                                                                                                                              bytes = read(sockfd, response + received, 1024);                                                                                                                                                                           if(bytes == 0)                                                                                                                                                                                                             {                                                                                                                                                                                                                              printf("read all data.\n\n");                                                                                                                                                                                              break;                                                                                                                                                                                                                 }                                                                                                                                                                                                                          if(bytes < 0)                                                                                                                                                                                                              {                                                                                                                                                                                                                              printf("bytes: %d\n", bytes);                                                                                                                                                                                              break;                                                                                                                                                                                                                 }                                                                                                                                                                                                                          received += bytes;                                                                                                                                                                                                         printf("received bytes: %d\n", bytes);                                                                                                                                                                                     int loc = 0;                                                                                                                                                                                                               if(parseRsp(response, received, loc))                                                                                                                                                                                      {                                                                                                                                                                                                                              printf("rsp body: %s\n", response + loc);                                                                                                                                                                                  break;                                                                                                                                                                                                                 }    }                
0 0
原创粉丝点击