快速理解TCP协议

TCP协议、IP协议、以太网协议

TCP协议是IP协议和以太网协议的上层协议,是应用层的协议的下层协议。

以太网协议: 规定了电子信号如何组成数据包,解决了局域网内部的点对点通信。
IP协议:IP协议可以连接多个局域网,实现了路由功能,允许某个局域网的A主机,向另一个局域网的B主机发送消息。IP协议只是一个地址协议,并不保证数据包的完整。如果存在路由器丢包(比如缓存满了,新进来的数据包就会丢失),此时就需要发现丢失了那个包,以及如何重新发送这个包。这就需要靠TCP协议。
TCP协议:保证数据通信过程中,数据包的完整性和可靠性,防止丢包。

TCP数据包的大小

以太网的数据包的到校是固定的,1522字节,其中1500字节是负载,22字节是头信息。
以太网负载内部存放IP数据包,IP数据包也有自己的头部信息,最少需要20字节,所以IP数据包最多有1480字节。
IP数据包的负载内部存放了TCP数据包,TCP数据包的头信息至少需要20字节,因此TCP数据包的最大负载是1460字节。由于IP和TCP协议往往有额外的头信息,所以TCP负载实际为1400字节左右。因此,一条1500字节的信息需要两个TCP数据包。
image.png

TCP数据包的编号(SEQ)

一个TCP包的负载只有1400字节,所以如果一次性发送大量数据,就必须分成多个包。比如,一个10MB的文件,需要发送7100多个包。TCP协议为每个包编号(SEQ),以便接收的一方按照顺序还原。万一发生丢包,也可以知道丢失了哪个包。
第一个包的编号是随机数。同时也会记录下一个包的编号信息(根据当前包的负载长度推算)。

TCP数据包的组装

收到TCP数据包以后,组装还原是操作系统完成的。应用程序不会直接处理TCP数据包。对于应用程序来说,不用关心数据通信的细节。除非线路异常,收到的总是完整的数据。应用程序需要的数据放在TCP数据包里面,有自己的格式(比如HTTP协议)。
操作系统不会处理TCP数据包里面的数据,只会负责做组装还原。一旦组装好TCP数据包,就会把它们转交给应用程序。TCP数据包里面有一个端口(port)参数,就是用来指定转交给监听该端口的应用程序。
应用程序收到组装好的原始数据,以浏览器为例,就会根据HTTP协议的 Content-Length 字段正确读出一段段的数据。这也意味着,一次TCP通信可以包括多个HTTP通信。

慢启动和ACK

服务器发送数据包,当然越快越好,最好一次性全发出去,但是如果发得太快,就有可能丢包。带宽小,路由器过热,缓存溢出等许多因素都会导致丢包。如果线路不好,发得越快,丢得越多。
最理想的状态就是在线路允许的情况下,达到最高的速率。此时就需要通过 慢启动 机制,慢慢尝试最优的速率。 慢启动 :开始的时候,发送得比较慢,然后根据丢包的情况,调整速率,如果不丢包,则加快发送速度;如果出现丢包,就降低发送速度。

Linux内核里面设定了常量 TCP_INIT_CWND ,刚开始通信的时候,发送方一次性发送10个数据包,即 发送窗口 的大小为10。然后停下来,等待接收方的确认,再继续发送。默认情况下,接收方每收到两个TCP数据包,就会发送一个确认消息 ACK
ACK 携带两个信息:
(1)期待要收到下一个数据包的编号。
(2)接收方的接收窗口的剩余容量。

数据包的遗失处理

TCP协议是要保证数据通信的完整性的。
所以对于数据包的遗失问题,TCP会在每个数据包里都带有下一个数据包的编号。如果下一个数据包没有收到,那么相应的ACK的编号就不会发生变化。
如果发送方收到三个连续重复的ACK(期待下一个数据包的起始编号),或者超时了还没有收到任何的ACK,就会确认丢包,那发送方就会重新发送这个包。
通过这种机制,TCP保证了不会有数据包的丢失。
image.png