TCP是一种流式协议

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。

流式协议的特点是什么?就像流水连续不断那样,消息之间没有边界。例如send了3条消息(这里的“消息”是指应用层的一个完整的协议包),分别是100字节、50字节、80字节,recv时可能收到的是230字节,就是说一次recv收到了3条消息,需要应用逻辑自己对recv到的数据进行分析,得出完整的消息。能一次recv到多个消息,也可能一次recv到一个半消息或半个消息,都是有可能的,这就是流式协议的特点。有的文章讲的粘包也是这个概念。

消息分包

既然TCP是一种流式协议,需要应用层自己来分析出完整的消息,那有哪些方式来确定一个完整消息呢?这个就是应用层通讯协议设计的工作了。

先看看最常见的HTTP协议是如何来分包的。HTTP协议是一种文本协议(非二进制协议),用\r\n\r\n来分割消息头和消息体,HTTP请求的消息头中有Content-Length来告知消息体有多大,如果没有该字段就表示无消息体,GET请求大多是这样。HTTP响应的消息头中,或者有Content-Length,或者有Transfer-Encoding: chunked告知以chunk模式分析消息体。

HTTP请求信息由3部分组成:

1、请求方法(GET/POST)、URI、协议/版本

2、请求头(Request Header)

3、请求正文,请求正文和请求头要有空行。这个空行必须存在,说明结束请求头传输,开始传输正文请求。

HTTP请求

GET/HTTP/1.1
[请求头]
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.;Window NT5.)
Accept-Encoding:gzip,deflate
[请求正文]
username=ring&password=

http响应格式

HTTP应答与HTTP请求相似,HTTP响应也由3个部分构成,分别是:

1、状态行

2、响应头(Response Header)

3、响应正文

HTTP响应1:Conetent-Length

HTTP/1.1 200 OK
SERVER: name
DATE: Fri, 22 Dec 2017 10:50:38 GMT
Content-Type: image/gif 
Content-Length: 43
Last-Modified: Mon, 1 Dec 2017 13:23:42 GMT
Connection: keep-alive
Expires: Fri, 22 Dec 2017 10:50:38 GMT
Cache-Control: max-age=0
Accept-Ranges: bytes GIF89a二进制数据 HTTP响应2:Transfer-Encoding
HTTP/1.1 200 OK
DATE: Fri, 22 Dec 2017 10:55:50 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Fri, 22 Dec 2017 10:55:50 GMT
Cache-Control: max-age=7200
Content-Encoding: gzip 91a
具体的数据
0

HTTP用\r\n\r\n来分割消息头和消息体,这种用特定字符/字符串来分割或分包的方式,还有不少协议用到。例如FTP/SMTP/POP3都是用\n来作为一个命令结束的标志。这种消息分包的方式,需要应用层去扫描已recv到的数据,性能上还不够高效,代码不严谨的还容易被攻击。在需要自定义协议的项目中,不少选择用二进制协议,解析高效,安全性更好些。

最简单的二进制协议分包方式是消息的头4个字节表示消息的总长度。这种方式还需要对最大消息长度做个限制,例如64K或1024K大小,避免超大数据包对接收方缓冲区的破坏。更进一步的,可以加入简单校验方法。例如消息头1个字节固定式0x2,消息的最后1个字节固定式0x3,消息总长度放在第2~5字节。这样收到完整消息后,如果头尾不是0x2和0x3,就直接异常处理。

协议设计

消息分包是协议设计的一个工作,协议设计的话题还不少,这里以HTTP协议为例,简要的说说里面设计的点,自己设计的协议也可以对照着有选择的使用,原理是共通的。

由消息头+消息体组成:空行分割HTTP head和body,HTTP头的每一行以\r\n结尾,空行就是\r\n\r\n
消息分包:如上所述,HTTP用Content-Length和Transfer-Encodeing来分包
消息压缩:请求中有Accept-Encoding字段,响应中用Content-Encoding字段表明压缩方式,一般采用gzip压缩
消息加密:https  (SSL: Secure Socket Layer)
消息ID:URL就是消息ID
响应的状态码:第一个数字定义了响应的类别。
    1xx:指示信息--表示请求已接收,继续处理
    2xx:成功--表示请求已被成功接收、理解、接受
    3xx:重定向--要完成请求必须进行更进一步的操作
    4xx:客户端错误--请求有语法错误或请求无法实现
    5xx:服务器端错误--服务器未能实现合法的请求
协议版本号: HTTP/1.1中的1.1就是HTTP 1.1版本
长连接:请求中Connection: keep-alive表示希望服务器保持连接,减少TCP连接的开销
字符集: Content-Type字段表明了字符集,例如: Content-Type: text/html; charset=gb2312
字符转义:URL中的参数需要做URL转义处理,例如http://xx.com/do?name=t%2F%3F%23%3Daa表示name为t/?#=aa

在我们自己设计协议时,可以有选择的使用,如果消息比较大,可以采用支持压缩;如果要兼容多个版本的协议,那版本号必不可少。如果采用二进制协议,字符集和字符穿衣的用处不大。

TCP、消息分包和协议设计的更多相关文章

  1. 主程的晋升攻略(4):TCP、消息分包和协议设计

    在<主程的晋升攻略(3):IP.DNS和CDN>中,一次网络请求经过DNS解析知道了目的IP,如今就要发出网络包,这里我们说一说TCP的相关话题. TCP是一种流式协议 讲网络编程的教科书 ...

  2. Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计

    http://blog.sina.com.cn/s/blog_48d4cf2d0101859x.html 谈谈网络编程中应用层(基于TCP/UDP)的协议设计 (2013-04-27 19:11:00 ...

  3. TCP协议设计原理

    TCP协议设计原理 最近去了解TCP协议,发现这是一个特别值得深思的协议.在本篇博客中,不会长篇大论的给大家介绍TCP协议特点.包头格式以及TCP的连接和断开等基本原理,而是会带大家深入理解为什么要这 ...

  4. Mina、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息

    在TCP连接开始到结束连接,之间可能会多次传输数据,也就是服务器和客户端之间可能会在连接过程中互相传输多条消息.理想状况是一方每发送一条消息,另一方就立即接收到一条,也就是一次write对应一次rea ...

  5. 分布式发布订阅消息系统 Kafka 架构设计[转]

    分布式发布订阅消息系统 Kafka 架构设计 转自:http://www.oschina.net/translate/kafka-design 我们为什么要搭建该系统 Kafka是一个消息系统,原本开 ...

  6. 2018-2019-1-20165221&20165225 《信息安全系统设计》实验五:通讯协议设计

    2018-2019-1-20165221&20165225 <信息安全系统设计>-实验五:通讯协议设计 OpenSSL学习: 简介: OpenSSL是为网络通信提供安全及数据完整性 ...

  7. python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)

    先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...

  8. im协议设计选型【转】

    一.im协议的分层设计所谓“协议”是双方共同遵守的规则,例如:离婚协议,停战协议.协议有语法.语义.时序三要素.(1)语法:即数据与控制信息的结构或格式(2)语义:即需要发出何种控制信息,完成何种动作 ...

  9. 网络编程基础socket 重要中:TCP/UDP/七层协议

    计算机网络的发展及基础网络概念 问题:网络到底是什么?计算机之间是如何通信的? 早期 : 联机 以太网 : 局域网与交换机 广播 主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无 ...

随机推荐

  1. java版微信公众号支付(H5调微信内置API)

    最近需要做微信公众号支付,网上找了大堆的代码,大多都只说了个原理,自己踩了太多坑,所有的坑,都会再下面的文章中标注,代码我也贴上最全的(叫我雷锋)!!! 第一步:配置支付授权目录 你需要有将你公司的微 ...

  2. SpringCloud微服务之跨服务调用后端接口

    SpringCloud微服务系列博客: SpringCloud微服务之快速搭建EurekaServer:https://blog.csdn.net/egg1996911/article/details ...

  3. Elasticsearch学习笔记——安装、数据导入和查询

    到elasticsearch网站下载最新版本的elasticsearch 6.2.1 ? 1 https://www.elastic.co/downloads/elasticsearch 中文文档请参 ...

  4. MysqL_select for update锁详解

    先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是InnoDB(至于为什么,后面再告诉你). 电商平台常见的下单场景: 一般商品表(goods)有基本的四个字段,id(主键),goods ...

  5. for each循环(增强for循环)

    底层实现是使用了迭代器,简化了迭代器的书写 格式: for(集合/数组的数据类型 变量名: 数组名/集合名) { // body } char[] chars = {'c', 'd', 'd', 'e ...

  6. 函数的作用域、global与nonlocal

    global 表示不再使用局部局部作用域中的内容,而是改用全局作用域中的变量 a = 100 def func(): global a # 表示不再局部创建这个变量,而是直接使用这个全局的a a = ...

  7. C++解决case中不能定义局部变量问题

    case Operation::DeviceAuthen: { std::string token = root["body"]["token"].asStri ...

  8. js强制将页面放到最大

    <!DOCTYPE html> <html> <head> <title></title> <script language=&quo ...

  9. PHP7语法知识(一):语言基础

    一.数据类型 1.字符串: 2.整形: var_dump函数:返回变量的数据类型和值. 3.浮点型: 4.布尔型: 5.数组: 6.对象: 7.NULL值 二.运算符 1.算术运算符: 2.递增递减运 ...

  10. windows平台下利用Nginx做负载均衡

    1.下载nginx(http://nginx.org/en/download.html)安装包,解压,并使用cmd命令转到nginx.exe所在的目录 2.执行cmd命令start nginx启动ng ...