文章目录

  • Pre
  • TCP 的拆包和粘包
    • TCP数据发送
    • TCP Segment
    • Sequence Number 和 Acknowledgement Number
    • MSS(Maximun Segment Size)
  • Question : TCP 协议是如何恢复数据的顺序的,TCP 拆包和粘包的作用是什么?


Pre

今天我们将从稳定性角度深挖 TCP 协议的运作机制

如今,大半个互联网都建立在 TCP 协议之上,我们使用的 HTTP 协议、消息队列、存储、缓存,都需要用到 TCP 协议——这是因为 TCP 协议提供了可靠性

简单来说,可靠性就是让数据无损送达。但若是考虑到成本,就会变得非常复杂——因为还需要尽可能地提升吞吐量、降低延迟、减少丢包率。

TCP 协议具有很强的实用性,而可靠性又是 TCP 最核心的能力 。具体来说,从一个终端有序地发出多个数据包,经过一个复杂的网络环境,到达目的地的时候会变得无序,而可靠性要求数据恢复到原始的顺序。这里先提出两个问题:

  • TCP 协议是如何恢复数据的顺序的?

  • 拆包和粘包的作用是什么?

那么带着这两个问题开始今天的学习。


TCP 的拆包和粘包

TCP数据发送

TCP 是一个传输层协议

TCP 发送数据的时候,往往不会将数据一次性发送

而是将数据拆分成很多个部分,然后再逐个发送。像下图这样:

同样的,在目的地,TCP 协议又需要逐个接收数据。

请 思考,TCP 为什么不一次发送完所有的数据?比如我们要传一个大小为 10M 的文件,对于应用层而言,就是一次传送完成的。而传输层的协议为什么不选择将这个文件一次发送完呢?

这里有很多原因,

  • 比如为了稳定性,一次发送的数据越多,出错的概率越大。
  • 再比如说为了效率,网络中有时候存在着并行的路径,拆分数据包就能更好地利用这些并行的路径。
  • 再有,比如发送和接收数据的时候,都存在着缓冲区。如下图所示:

缓冲区是在内存中开辟的一块区域,目的是缓冲。因为大量的应用频繁地通过网卡收发数据,这个时候,网卡只能一个一个处理应用的请求。当网卡忙不过来的时候,数据就需要排队,也就是将数据放入缓冲区。如果每个应用都随意发送很大的数据,可能导致其他应用实时性遭到破坏。

还有一些原因 比如内存的最小分配单位是页表,如果数据的大小超过一个页表,可能会存在页面置换问题,造成性能的损失。

总之,方方面面的原因:在传输层封包不能太大

这种限制,往往是以缓冲区大小为单位的。也就是 TCP 协议,会将数据拆分成不超过缓冲区大小的一个个部分。每个部分有一个独特的名词,叫作 TCP 段(TCP Segment)

在接收数据的时候,一个个 TCP 段又被重组成原来的数据。

像这样,数据经过拆分,然后传输,然后在目的地重组,俗称拆包。所以拆包是将数据拆分成多个 TCP 段传输。

那么粘包是什么呢?有时候,如果发往一个目的地的多个数据太小了,为了防止多次发送占用资源,TCP 协议有可能将它们合并成一个 TCP 段发送,在目的地再还原成多个数据,这个过程俗称粘包。所以粘包是将多个数据合并成一个 TCP 段发送


TCP Segment

那么一个 TCP 段长什么样子呢?下图是一个 TCP 段的格式:

我们可以看到,TCP 的很多配置选项和数据粘在了一起,作为一个 TCP 段。

显然, 把每一部分都记住似乎不太现实,先把其中最主要的部分理解。

TCP 协议就是依靠每一个 TCP 段工作的,所以你每认识一个 TCP 的能力,几乎都会找到在 TCP Segment 中与之对应的字段。 接下来 认识它们。

  • Source Port/Destination Port 描述的是发送端口号和目标端口号,代表发送数据的应用程序和接收数据的应用程序。比如 80 往往代表 HTTP 服务,22 往往是 SSH 服务……

  • Sequence Number 和 Achnowledgment Number 是保证可靠性的两个关键

  • Data Offset 是一个偏移量。这个量存在的原因是 TCP Header 部分的长度是可变的,因此需要一个数值来描述数据从哪个字节开始。

  • Reserved 是很多协议设计会保留的一个区域,用于日后扩展能力。

  • URG/ACK/PSH/RST/SYN/FIN 是几个标志位,用于描述 TCP 段的行为。也就是一个 TCP 封包到底是做什么用的

1)URG 代表这是一个紧急数据,比如远程操作的时候,用户按下了 Ctrl+C,要求终止程序,这种请求需要紧急处理。

2)ACK 代表响应, 所有的消息都必须有 ACK,这是 TCP 协议确保稳定性的一环。

3)PSH 代表数据推送,也就是在传输数据的意思。

4)SYN 同步请求,也就是申请握手。

5)FIN 终止请求,也就是挥手。

特别说明一下:以上这 5 个标志位,每个占了一个比特,可以混合使用。比如 ACK 和 SYN 同时为 1,代表同步请求和响应被合并了。这也是 TCP 协议,为什么是三次握手的原因之一

  • Window 也是 TCP 保证稳定性并进行流量控制的工具,后续会 TCP 的稳定性:滑动窗口和流速控制是中详细介绍。

  • Checksum 是校验和,用于校验 TCP 段有没有损坏。

  • Urgent Pointer 指向最后一个紧急数据的序号(Sequence Number)。它存在的原因是:有时候紧急数据是连续的很多个段,所以需要提前告诉接收方进行准备。

  • Options 中存储了一些可选字段,比如接下来我们要讨论的 MSS(Maximun Segment Size)。

  • Padding 存在的意义是因为 Options 的长度不固定,需要 Pading 进行对齐。


Sequence Number 和 Acknowledgement Number

在 TCP 协议的设计当中,数据被拆分成很多个部分,部分增加了协议头。合并成为一个 TCP 段,进行传输。这个过程,我们俗称拆包。这些 TCP 段经过复杂的网络结构,由底层的 IP 协议,负责传输到目的地,然后再进行重组。

这里请你思考一个问题:稳定性要求数据无损地传输,也就是说拆包获得数据,又需要恢复到原来的样子。而在复杂的网络环境当中,即便所有的段是顺序发出的,也不能保证它们顺序到达,因此,发出的每一个 TCP 段都需要有序号。这个序号,就是 Sequence Number(Seq)


如上图所示。发送数据的时候,为每一个 TCP 段分配一个自增的 Sequence Number。接收数据的时候,虽然得到的是乱序的 TCP 段,但是可以通过 Seq 进行排序。

但是这样又会产生一个新的问题——接收方如果要回复发送方,也需要这个 Seq。而网络的两个终端,去同步一个自增的序号是非常困难的。因为任何两个网络主体间,时间都不能做到完全同步,又没有公共的存储空间,无法共享数据,更别说实现一个分布式的自增序号了。

其实这个问题的本质就好像两个人在说话一样,我们要确保他们说出去的话,和回答之间的顺序。因为 TCP 是一个双工的协议,两边可能会同时说话。所以聪明的科学家想到了确定一句话的顺序,需要两个值去描述——也就是发送的字节数和接收的字节数

我们重新定义一下 Seq(如上图所示),对于任何一个接收方,如果知道了发送者发送某个 TCP 段时,已经发送了多少字节的数据,那么就可以确定发送者发送数据的顺序。

但是这里有一个问题。如果接收方也向发送者发送了数据请求(或者说双方在对话),接收方就不知道发送者发送的数据到底对应哪一条自己发送的数据了。

举个例子:下面 A 和 B 的对话中,我们可以确定他们彼此之间接收数据的顺序。但是无法确定数据之间的关联关系,所以只有 Sequence Number 是不够的。

A:今天天气好吗?A:今天你开心吗?B:开心B:天气不好

人类很容易理解这几句话的顺序,但是对于机器来说就需要特别的标注。因此我们还需要另一个数据,就是每个 TCP 段发送时,发送方已经接收了多少数据。用 Acknowledgement Number 表示,下面简写为 ACK。

下图中,终端发送了三条数据,并且接收到四条数据,通过观察,根据接收到的数据中的 Seq 和 ACK,将发送和接收的数据进行排序。


例如上图中,发送方发送了 100 字节的数据,而接收到的(Seq = 0 和 Seq =100)的两个封包,都是针对发送方(Seq = 0)这个封包的。发送 100 个字节,所以接收到的 ACK 刚好是 100。说明(Seq= 0 和 Seq= 100)这两个封包是针对接收到第 100 个字节数据后,发送回来的。这样就确定了整体的顺序

注意,无论 Seq 还是 ACK,都是针对“对方”而言的。是对方发送的数据和对方接收到的数据 。 我们在实际的工作当中,可以通过 Whireshark 调试工具观察两个 TCP 连接的 Seq和 ACK。


MSS(Maximun Segment Size)

接下来,我们讨论下 MSS,它也是面试经常会问到的一个 TCP Header 中的可选项(Options),这个可选项控制了 TCP 段的大小,它是一个协商字段(Negotiate)。协议是双方都要遵循的标准,因此配置往往不能由单方决定,需要双方协商。

TCP 段的大小(MSS)涉及发送、接收缓冲区的大小设置,双方实际发送接收封包的大小,对拆包和粘包的过程有指导作用,因此需要双方去协商

如果这个字段设置得非常大,就会带来一些影响。

  • 首先对方可能会拒绝,作为服务的提供方,你可能不会愿意接收太大的 TCP 段。因为大的 TCP 段,会降低性能,比如内存使用的性能。 还有就是资源的占用。一个用户占用服务器太多的资源,意味着其他的用户就需要等待或者降低他们的服务质量

  • 其次,支持 TCP 协议工作的 IP 协议,工作效率会下降

TCP 协议不肯拆包,IP 协议就需要拆出大量的包。那么 IP 协议为什么需要拆包呢?这是因为在网络中,每次能够传输的数据不可能太大,这受限于具体的网络传输设备,也就是物理特性。但是 IP 协议,拆分太多的封包并没有意义。因为可能会导致属于同个 TCP 段的封包被不同的网络路线传输,这会加大延迟。同时,拆包,还需要消耗硬件和计算资源。

那是不是 MSS 越小越好呢?MSS 太小的情况下,会浪费传输资源(降低吞吐量)。因为数据被拆分之后,每一份数据都要增加一个头部。如果 MSS 太小,那头部的数据占比会上升,这让吞吐量成为一个灾难。所以在使用的过程当中,MSS 的配置,往往都是一个折中的方案

不要去猜想什么样的方案是最合理的,而是要尝试去用实验证明它,一切都要用实验依据说话。


Question : TCP 协议是如何恢复数据的顺序的,TCP 拆包和粘包的作用是什么?

Answer:

TCP 拆包的作用是将任务拆分处理,降低整体任务出错的概率,以及减小底层网络处理的压力。拆包过程需要保证数据经过网络的传输,又能恢复到原始的顺序。这中间,需要数学提供保证顺序的理论依据。 TCP 利用(发送字节数、接收字节数)的唯一性来确定封包之间的顺序关系

粘包是为了防止数据量过小,导致大量的传输,而将多个 TCP 段合并成一个发送。

计网 - TCP 的封包格式:TCP 为什么要粘包和拆包?相关推荐

  1. [网络知识]TCP协议中的粘包与拆包

    在平时客户端socket开发中,如果客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数据包粘在一起的情况,这就是TCP协议中经常会遇到的粘包以及拆包的问题. 我们都知道TCP属于传输层 ...

  2. 20-Netty TCP 粘包和拆包及解决方案

    TCP粘包和拆包的基本介绍 TCP是面向连接的, 面向流的, 提供可靠性服务, 收发两端(客户端和服务器端) 都有一一成对的Socket,因此发送端为了将多个发给接收端的包, 更有效的发给对方, 使用 ...

  3. TCP粘包、拆包与解决方案、C++ 实现

    说明: TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了 ...

  4. TCP的粘包和拆包及Netty中的解决方案

    1.基本介绍 TCP 是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的 socket, 因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(N ...

  5. TCP粘包和拆包原因

    最近研究Netty网络编程,以前项目中页遇到过数据接收过程中数据质量太差问题,很可能是TCP传输过程中问题,特此记录. 问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包 ...

  6. Socket通用TCP通信协议设计及实现(防止粘包,可移植,可靠)

    Socket通用TCP通信协议设计及实现(防止粘包,可移植,可靠) 引文 我们接收Socket字节流数据一般都会定义一个数据包协议.我们每次开发一个软件的通信模块时,尽管具体的数据内容是不尽相同的,但 ...

  7. TCP 粘包和拆包及解决方案

    TCP 粘包和拆包基本介绍 1.TCP 是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的 socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使 ...

  8. TCP中的粘包、拆包问题产生原因及解决方法

    目录 粘包/拆包 问题产生原因: 解决 粘包/拆包 问题: 为什么TCP有粘包? 为什么UDP没有粘包? 发生在网络的哪些层上? 粘包/拆包 问题产生原因: 发生TCP粘包或拆包有很多原因,现列出常见 ...

  9. 【Netty】TCP粘包和拆包

    一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...

最新文章

  1. linux系统core dump设置,linux coredump设置
  2. 爬取股票信息(股票代码+价格)
  3. 新特性的副产品--从11g的DEFERRED SEGMENT CREATION说起
  4. 【译】How I hacked Google’s bug tracking system itself for $15,600 in bounties
  5. 数据库设计与开发概述
  6. 互动场景下的低延迟编码技术
  7. mapreduce 算法_MapReduce算法–顺序反转
  8. 香港中文大学(深圳)张大鹏教授访谈
  9. mysql 中文字段排序( 按拼音首字母排序) 的查询语句
  10. Spring-Jpa : @MappedSuperclass的作用
  11. 如何把 Google adsense 的广告放到博客的Banner位置
  12. 初识 Node.js
  13. js判断一个元素是否在数组中存在
  14. Linux启动阶段Grub损坏修复
  15. JavaScript(js)基础
  16. 李沐的深度学习笔记来了!
  17. mini《猜字》游戏,谁玩谁迷糊
  18. 喷墨打印机的使用 hp LaserJet 1010 HB 打印顺序
  19. html5统计鼠标点击的次数,怎么实现js统计鼠标点击次数
  20. 字符串format拼接格式化

热门文章

  1. ListView控件的基本使用(方式一:使用ArrayAdapter适配器实现)
  2. Android自定义View实践 空气质量检测 pm2.5
  3. 好看的html导航栏作品,精选10款超酷的HTML5/CSS3菜单
  4. c语言字符串去重简单,C语言实现简单飞机大战
  5. git stash 个人理解
  6. python break -else 语句
  7. io密集型和cpu密集型java,如何设计CPU密集型与I/O密集型程序
  8. Tableau必知必会之如何用颜色 突显 前N项和后N项
  9. Flink从入门到精通100篇(二)-在Linux中完整安装flink并做Flink文件的配置
  10. MATLAB基本操作(五):MATLAB中的逻辑运算及all(),any()的使用