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. Web API中的返回值类型

    WebApi中的返回值类型大致可分为四种: Void/ IHttpActionResult/ HttpResponseMessage /自定义类型 一.Void void申明方法没有返回值,执行成功后 ...

  2. Spring Boot 2程序不能加载 com.mysql.jdbc.Driver 问题

    用Spring Boot Starter 向导生成了一个很简单SpringBoot程序, 用到了 MySQL, 总是下面不能加载 Mysql driver class 错误. Cannot load ...

  3. Java入门系列Java NIO

    jdk1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它可以调用Native方法直接分配堆外内存,这个堆外内存就是本机内存,不会影响到堆内存的大小.

  4. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  5. [C++]数组处理相关函数(memcpy/memset等)

    头文件:string.h或者memory.h [1]void *memcpy(void *dest, const void *src, size_t n);//数组元素拷贝 功能:从源src所指的内存 ...

  6. [C++]2-5 分数化小数

    /* 分数化小数 输入正整数a,b,c,输出a/b的小数形式.精确到小数点后C位.a,b<=10^6,c<=10^6. 输入包含多组数据,结束标记为a=b=c=0 样例输入: 1 6 4 ...

  7. Java SE之正则表达式一:概述

    正则表达式 概念 定义:符合一定规则的表达式 作用:用于专门操作字符串 特点:用于一些特定的符号表示代码的操作,这样就简化了长篇的程序代码 好处:可以简化对字符串的复杂操作 弊端:符号定义越多,正则越 ...

  8. luogu P3162 [CQOI2012]组装

    传送门 mdzz,为什么这题有个贪心的标签啊qwq 首先考虑每一种车间,对于每相邻两个车间,在中点左边那么左边那个会贡献答案,在右边就右边那个更优 所以总共会有m-1个这样的分界中点,然后最多有m+1 ...

  9. [MVC框架]利用@Scheduled注解创建定时执行的程序

    新写的项目中有一个地方要用到定时器,然后就用了spring的@Scheduled注解,顺手就给记录下来了,免得下次用的时候还要翻以前的项目,顺便分享出来,给没用过的兄弟姐妹们做个参考. 这次主要用的是 ...

  10. NPOI 列宽自适应 代码示例

    //列宽自适应,只对英文和数字有效 for (int i = 0; i <= maxColumn; i++) { sheet.AutoSizeColumn(i); } //获取当前列的宽度,然后 ...