上章 通过一段小对话,介绍了 client、server 和 network 之间,为了保证 TCP 数据传输的可靠性和效率进行的沟通和优化,并提及了相关的专业术语,本章将对相关的专业术语进行说明。
ISN
TCP 三次握手的过程中,除了通过三次握手让 client 和 server 正确建立连接外,同时也交换彼此的初始序列号 ISN(c) 和 ISN(s)。
1.ISN 的特点:初始化具有随机性
2.ISN 的一种生成规则:
RFC1948 中提出了一个较好的初始化序列号 ISN 随机生成算法:
ISN = M + F(localhost, localport, remotehost, remoteport)
M 是一个计时器,这个计时器每隔4毫秒加1。
F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值。
3.ISN 的作用:
(1)每次建立连接前重新初始化一个序列号主要是为了通信双方能够根据序号将不属于本连接的报文段丢弃。
(2)作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序。
ACK
在 client 和 server 通信过程中,client 和 server 需要通过一种方式来确定对方是否已正确接收数据。TCP 中通过 ACK 机制实现,每一次的数据通信,如果对方已接收数据,都会返回一个ACK。
ACK 值:ACK = 当前通信序列号+1。
ACK作用:
(1)当 client 接收到 ACK 时,会通过该值来确定哪些数据被正确接收,以保证不重复发送。
(2)client 在接收到重复 ACK 且超过阈值,会触发快速重传机制,而不必等到超时之后才重传。
重传机制
在 TCP 协议中,因为网络不可信,不仅会出现乱序,也会出现丢包的情况。当出现丢包时,需要重传。在 TCP 中通过三种方案实现。
1.基于时间的超时重传。每次数据通信都会设置一个超时,当在指定时间没有接收到对应 ACK 时,会触发重传。
2.基于累计 ACK 的快速重传。当重复收到相同的 ACK 3次,会触发快速重传机制。
3.由于 2 中,在一次 RTT 过程中至多只能重传一个数据包,在存在连续数据包丢失的场景中,需要重复2的过程。采用 SACK,ACK 可以包含额外信息。使得发送端在每个 RTT 时间内可以填补多个空洞。
注:由于 TCP options 最大的长度是40字节,那么其所表示的 SACK 的数量最多是4(4*8+2 = 34),同时由于 SACK 有些时候会和时间戳(占10字节)一起用,因此,此种情况下最多只有3个 SACK。
流量窗口
在发送数据过程中,有时候 client 的发送速率过快,超出 sever 的接收能力。 为了解决这个问题,server 会通过窗口通知(awnd),告知 client, 而 client 也通过 awnd 和 cwnd(拥塞窗口) 这两个字段决定当前的流量窗口大小(W) W = min(awnd,cwnd)。其中包括几个操作:
1.流量控制,client 保证发送的数据不超过 W(未发送+已发送未确认)
2. ACK 确认之后,窗口会滑动
3. 窗口扩展/收缩, 根据 awnd 和 cwnd 动态调整窗口大小。
注:具体流程可参考:https://mp.weixin.qq.com/s/h89R86KhWiQKsBvfZpyF5Q
拥塞控制
网络是复杂的,一个数据发送从 client 到 server,需要经历 N 个节点(路由器/交换机...)。而每个节点的数据处理能力也各有不同,所以流量窗口的控制,还需要考虑搜经过的节点的处理能力。
且不同于server,server 可以通过接收窗口告知 client 它的处理能力,但网络中的节点不能。因此需要 client 自己进行探测,同时结合接收窗口(awnd),来找到一个最佳流量窗口。拥塞控制主要通过三种算法实现(只是算法的一种)
慢启动
慢启动过程如下:
1.初始化 cwnd = 1,表明可以传一个 MSS 大小的数据。
2.每当收到一个 ACK,cwnd++; 呈线性上升 。
3.每当过了一个 RTT,cwnd = cwnd*2; 呈指数让升。
4.还有一个 ssthresh(slow start threshold),是一个上限,当 cwnd >= ssthresh 时,就会进入“拥塞避免算法”
注:MSS(最大报文段长度)是 TCP 协议的一个选项,用于在 TCP 连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度
拥塞避免
拥塞避免过程如下:
1.收到一个 ACK 时,cwnd = cwnd + 1/cwnd。
2.当每过一个 RTT 时,cwnd = cwnd + 1
快速恢复
快速恢复过程如下:
1.当发送方连续收到三个重复 ACK 时,执行乘法减小算法,将慢启动门限(sshthresh )减半。这是为了预防网络发生拥塞。
2.sshthresh = sshthresh /2 (乘法减少) 。
3.cwnd = sshthresh。
4.进入加法增加, 乘法减少的 拥塞避免算法。
参考
1.《TCP/IP 详解 卷一》 13章至17章
2.https://mp.weixin.qq.com/s/h89R86KhWiQKsBvfZpyF5Q