TCP 协议详解
概述
本文基于 TCP 协议报文格式深入讲解,学习它的三次握手、四次挥手、滑动窗口等机制,帮助理解底层通信原理。
![图片]
![图片]
一、TCP 协议格式
TCP 全称为传输控制协议(Transmission Control Protocol)。人如其名,要对数据的传输进行详细的控制。
1. 十六位窗口大小
对于 TCP 来说,如果接收缓冲区满了,再发送机会被丢弃。因此发送前需要知道对方的接收缓冲区的剩余长度。按量按需发送,必须知道对方的接收缓冲区中剩余空间的大小,因此每次发送的 TCP 报文都要带有自己剩余接收缓冲区的长度。
2. 四位首部长度
首先我们要知道 TCP 光报头就至少 20 字节(不包含选项)。对于 4 位首部长度最多是 0-15,因此可以推导出表示的范围是 [0, 60],真正报头的长度是与它为 4 倍关系。也就是首部长度最少就是 5,也就是 101。
此时有个疑问:得到对应的 TCP 直接读取首部长度然后越过这些字节往后读,就是正文了,那么有报头大小,报文大小呢?
对于 UDP 它是面向用户数据报的,需要一次性发全部与读取,因此需要报文大小;但是 TCP 它是面向字节流的,因此如何读,读多少都交给用户自己控制。如果带了报文大小就一定是读取到完整的,而 TCP 是面向字节流,读取的时候需要控制,可能不完整,因此为了符合特性无正文大小。
下面再提下 TCP 的可靠性:
目前可以把 TCP 通信过程理解成这样(后续会变化):
![图片]
- TCP 这种应答机制保证对历史消息的可靠性。
- 通信中,最新的报文,永远没有应答,最新可靠性无法保证。
- 因此如果让 TCP 发的那些消息可靠,因此只需要确保你要保证可靠的消息不是最新消息即可。
但是实际是这样的:
![图片]
- 接受方收到的指定报文序号之前的所有的信息,下一次发送,从确认序号开始(确认序号 = 序号 + 1,当只有一字节数据可以这么理解)。
为什么会有两个序号啊,一个序号就可以吧?
- 应答也是 TCP 报文自己也要有序列号,比如说 s 给 c 发了一个信息序号是 9,此时 s 回复的也是第 9 条然后确认序号就是 10,此时告诉 s 第 9 条正常接收,下一次从 10 开始发送。
此外还可以补充一点:应答也是有数据的,也是可以承载发送的信息的(因为每次都是以 TCP 形式发送,肯定可以携带答复信息 (当确认应答的时候))。
其他通信过程的重点及细节我们后续再谈。
3. 标记位
URG:紧急指针是否有效。ACK:确认号是否有效。PSH:提示接收端应用程序立刻从 TCP 缓冲区把数据读走。RST:对方要求重新建立连接;我们把携带 RST 标识的称为复位报文段。SYN:请求建立连接;我们把携带 SYN 标识的称为同步报文段。FIN:通知对方,本端要关闭了,我们称携带 FIN 标识的为结束报文段。
这里本质就是报头中的比特位,确定不同状态有不同处理方式。
认识下它,也就是三次握手与四次挥手:
首先请看图:
![图片]
- 以上就是三次握手,四次挥手的简化版。
- 根据握手存在时间线:因此明白客户端知道服务端能收能发与服务端确定客户端能收能发存在时间间隔。
- 前两次握手,不能携带数据,因为三次握手没有完成,第三次可以携带数据,但是三次握手好了不一定立刻发消息(比如最后一次 ACK 不一定带消息,比如等一会再发)。
那么为什么要进行三次握手呢?
- 因为三次握手才确定了:服务端确定客户端能发能收,客户端确定服务端能发能收,这样才能说明双方互相通信没问题。
对于四次挥手:互相知道对方想断开连接,并互相同意!
上面是成功的情况,但是有没有可能失败?
如下图所示的情况:
![图片]
- 比如此时当服务端确定客户端能收到的那个 ACK 丢包了,此时 client 接下来就会给 server 发数据,但是 server 还没确定好 三次握手完成,因此此时收到对应数据,就会立刻给 client 发送 RST。(此次连接失败了!)


