TCP 的特点

  1. 面向连接,TCP 连接是一条逻辑连接
  2. 只能一对一传输
  3. 提供可靠交付服务
  4. 全双工通信
  5. 面向字节流,将应用层交付的一次一个数据块仅看作一连串的无结构字节流

TCP 报文段

字段长度描述
源端口和目的端口各 2B发送方和接收方的端口
序号4B本报文段发送的第一个字节的序号
确认号4B期望收到对方下一个报文段的第一个字节的序号
数据偏移4bit表示 TCP 报文的数据起始处距离报文起始处距离多远,也就是表示首部长度,单位是 4B
保留6bit置为 0,保留到今后使用
紧急位 URG1bitURG=1 则表明该报文段中有紧急数据,紧急数据在数据部分的最前面,根据紧急指针字段判断紧急数据有多少字节
确认位 ACK1bitACK=1 时,确认号字段才有效。TCP 连接建立后,ACK 应该一直置一
推送位 PSH1bit接收方 TCP 收到 PSH=1 的报文后,尽快交付接收应用进程,而不再等到缓存填满后才向上交付
复位位 RST1bitRST=1 表示 TCP 连接出现严重差错,需要释放连接,重新建立连接。也可以用于拒绝一个非法报文段
同步位 SYN1bitSYN=1 表示这是一个连接请求或连接接收报文
终止位 FIN1bitFIN=1 表示发送方的数据已发送完毕,请求释放连接
窗口2B剩余接收窗口大小,单位为 B
检验和2BUDP 一样,要在 TCP 前面加上伪首部,再计算整个报文的检验和
紧急指针2B仅在 URG=1 时才有效,表示数据部分开头紧急数据的字节数
选项0~40B额外选项,如最大报文段长度 MSS 表示数据部分的最大长度(不包括首部)
填充填充使整个首部长度为 4B 的整数倍

TCP 连接管理

连接建立

第一次“握手”:客户端主动发送 SYN=1 的连接请求报文段,并确定一个初始序号 seq=x,SYN 报文段不携带数据,但要消耗一个序号

第二次“握手”:服务器收到后返回 ACK=1 表示确认收到请求,SYN=1 表示这是连接请求报文段,确认一个初始序号 seq=y,ack=x+1 表示客户端可以开始发送下一个报文段。

第三次“握手”:客户端收到后返回 ACK=1 表示确认收到回应,可以开始从序号 x+1 开始发送报文段,并期望收到服务端的下一个报文段 y+1,也可以不发送数据。

Tip

第三次握手时就可以开始发送数据。

连接释放

第一次“挥手”:打算关闭连接时,客户端主动发送 FIN=1 的释放连接报文,seq 为上一次发送数据的最后一个字节的序号+1 ,FIN 报文段虽然不携带数据,但是也要消耗一个序号

第二次“挥手”:服务端收到后,回复 ACK=1 表示收到,ack 表示收到客户端的数据,seq 为服务端上一次发送数据的最后一个字节的序号+1 。

Tip

此时,从客户端到服务端的连接已经单向关闭,但是 TCP 连接是全双工连接,所以服务端在发完要发的数据后也要主动关闭连接。

第三次“挥手”:服务端发完要发的数据后,主动发送 FIN=1 的释放连接报文段,ACK=1,seq 为刚刚发完的最后一个序号+1,ack 希望收到客户端的下一个序号的报文段。

第四次“挥手”:客户端收到后,ACK=1,发送下一个 seq 序号,并期望收到服务端下一个序号的报文。客户端发送该报文之后,进入 TIME-WAIT 状态,等待 2 倍的 **MSL(最长报文段寿命)**之后,关闭连接。而服务器端在收到该报文后直接关闭连接。

Tip

保活计时器:避免服务器在客户机突然故障时一直等待。 时间等待计时器:在 TIME-WAIT 阶段使用,其值设置为最长报文段寿命的两倍 2MSL。

TCP 可靠传输

TCP 连接传送的数据流中的每个字节都有一个序号,TCP 报文的序号字段的值是该报文发送的数据的第一个字节的序号。

TCP 默认使用累计确认,即收到确认号为 u,则表示序号在 u 之前的字节已经全部正确到达。

冗余 ACK:TCP 规定每当比期望序号大的失序报文段到达时,就发送一个冗余 ACK,指明下一个期待字节的序号。当发送方连续收到 3 个期望同一序号的冗余 ACK 时,就直接认为在期待的字节后面的这个字节数据已经丢失。

只有失序到达才返回冗余 ACK,首次收到的请求序号的报文不计入冗余 ACK。

超时和冗余 ACK会导致 TCP 对报文段进行重传。

Tip

使用重传计时器进行计时。

TCP 流量控制

数据链路层的流量控制相似,传输层 TCP 的流量控制也使用滑动窗口机制

传输层和数据链路层的流量控制的区别:

范围接收窗口大小
传输层端到端可以动态变化
数据链路层点到点固定

三种确认机制的对比:

协议确认机制对失序报文的处理
TCP累积确认缓存起来,并发送冗余 ACK
GBN累积确认直接丢弃
选择重传每一帧单独确认缓存起来

Tip

TCP 流量控制相当于 GBN 和选择重传 SR 的结合。

零窗口持续计时器

为了打破非零窗口通知报文段丢失而引起的双方,互相等待的死锁局面,TCP 为每个连接都设有一个持续计时器

  • TCP 的一方收到零窗口通知后启动持续计时器
  • 计时器超时时,发送一个零窗口探测报文段,仅携带 1 字节数据
  • 对方在确认时,给出最新的接收窗口值
  • 如果最新的 rwnd 还是 0,则重新进行这个流程

Tip

相当于发一个携带 1 字节数据的报文来试探,以此重新获得对方的 ACK,其中包含了窗口值。

TCP 拥塞控制

TCP 还要求发送方维护一个拥塞窗口(cwnd),大小取决于网络的拥塞程度,并且动态变化。

网络不拥塞时,不需要拥塞控制,所以只需要和 TCP 流量控制一样,接收窗口 rwnd 是多少发送窗口 swnd 就是多少。网络拥塞的时候就要考虑拥塞窗口 cwnd

拥塞控制的算法有四种:慢开始、拥塞避免、快重传和快恢复。这些算法都是根据网络拥塞情况动态调整拥塞窗口 cwnd 的算法

设置一个慢开始门限 ssthresh,在 ssthresh 之前使用慢开始,在 cwnd 大于 ssthresh 时使用拥塞避免。发生超时后 ssthresh=当前 cwnd/2

  • 慢开始:cwnd 从 1 开始,每经过一个 RTT 乘 2,指数级增长
  • 拥塞避免:每经过一个 RTT,cwnd+1
  • 快重传:发送方一旦连续收到 3 个冗余 ACK(即重复确认),就立即重传相应的报文段,而不是等待超时才重传。
  • 快恢复:将 cwnd 和 ssthresh 都设置为当前 cwnd 的一半,然后直接开始拥塞避免算法

总结:TCP 连接刚建立和网络出现超时时,使用慢开始和拥塞避免算法;当发送方收到 3 个冗余 ACK 时,采用快重传和快恢复算法。

慢开始的 cwnd 增大机制

慢开始在每收到一个对新的报文段的确认后,把拥塞窗口增加之多一个 MSS 的数值,用这样的方法逐步增大发送方的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。体现在时间上就是每经过一个传输轮次 RTT,cwnd 乘 2

TCP 的发送窗口

经过流量控制和拥塞控制的双重限制,TCP 最终的发送窗口的上限值=min{rwnd, cwnd}