之前几篇文章都是介绍了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.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie: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=12314353
Host:www.baidu.com
Upgrade-Insecure-Requests:1
User-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;                                                                                                                                                                                                         }}                

【socket】socket介绍-socket与http服务通信相关推荐

  1. socket()函数介绍

    socket()函数介绍 socket函数介绍 函数原型 domain type protocol errno 示例 函数原型 socket()函数的原型如下,这个函数建立一个协议族为domain.协 ...

  2. 在服务器端调用微软office接口,Office 365 服务通信 API 参考

    Office 365 服务通信 API 参考 2021/8/11 本文内容 重要 Microsoft Graph 中的服务运行状况和通信 API 现已推出. Microsoft Graph API 替 ...

  3. QT中使用C++ socket通信(了解socket通信、socket的三次握手和四次挥手、socket函数说明、客户端与服务端的代码实例)

    一.TCP/IP协议四个抽象层: 二.socket位置 socket就在应用程序的传输层和应用层之间,传输层的底一层的服务提供给socket抽象层,socket抽象层再提供给应用层. 三.socket ...

  4. socket不能bind请求的地址_socket通信原理

    一.什么是Socket? 1.Socket是一个网络通信的套接字(接口) 二.Socket的实现流程? 1.Socket在客户端和服务端发生了什么? 服务器:a.socket()创建socket对象b ...

  5. 1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

     1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端 ...

  6. 什么是套接字?Socket基本介绍

    什么是套接字?Socket基本介绍 一.什么是套接字? 二.套接字特性 三.套接字缓冲区 一.什么是套接字? 套接字是一种通信机制(通信的两方的一种约定),socket屏蔽了各个协议的通信细节,提供了 ...

  7. php cannot bind port to socket,PHP基于socket实现客户端和服务端通讯功能

    本文主要介绍了PHP基于socket实现的简单客户端和服务端通讯功能,可实现服务端接收客户端发送的字符串进行翻转操作后返回客户端的功能,需要的朋友可以参考下 服务端: set_time_limit(0 ...

  8. java socket 端口_Java Socket通信如何摆平自身端口问题

    Java Socket通信在使用的时候有不少的问题,在端口编程上来说是一个十分重要的.下面我们就看看Java Socket通信如何才能更好的使用相关的代码.希望大家有所帮助. 事实上网络编程简单的理解 ...

  9. android传递socket对象,Android Socket通信详解

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时 ...

  10. 【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序

    结合多线程实现socket 使用非线程池(拓展Thread) 使用线程池(Executor pool) 使用DatagramPacket DatagramSocket开发UDP/IP程序 使用UDP获 ...

最新文章

  1. @Conditional派生注解
  2. 安卓高手之路之 ClassLoader
  3. 计算机四级考试操作系统单元题,计算机四级考试操作系统单选练习
  4. 机器学习-损失函数 (转)
  5. Linux设备驱动程序概念
  6. 1.1 MySQL OCP 实战环境准备
  7. cf1207解题报告
  8. python库读取cif文件_Pymatgen读/写各种文件,pymatgen,读写
  9. unique函数_C++核心准则C.35:基类的析构函数必须满足的条件
  10. matlab检查错误 函数,检查代码中的错误和警告
  11. 如何获取k8s拓扑_k8s从安装到精通--Service 拓扑介绍
  12. vue/iview使用moment.js
  13. 3.1 Zend_Db_Adapter
  14. 封装一个FTPClient连接池工具类
  15. LCA(最近公共子序列)
  16. RxBinding系列之RxTextView(二)
  17. DB2 数据库的备份与还原
  18. A DIRT-T APPROACH TO UNSUPERVISED DOMAIN ADAPTATION
  19. webrtc实现局域网网页视频聊天
  20. 硬链接与软连接的区别_(转)

热门文章

  1. 方差分析 球形检验_spss球形检验.PDF
  2. 高等数学(第七版)同济大学 习题11-2 个人解答
  3. Archlinux和Windows双系统安装
  4. 大话卫星导航中的信号处理系列文章——GPS信号L1频点的中频数据生成与验证
  5. execv 函数的应用
  6. 汉锐4K广播专业会议摄像机
  7. MySQL 与 PostgreSQL 比较,哪个更好、我们该选用哪个?
  8. Python函数——Numpy size()
  9. Matlab--intersect
  10. HDU 4069 Squiggly Sudoku 【DLX+BFS】