上一篇内容可能比较多,显得比较杂乱,这一篇简单总结一下TCP是靠什么实现可靠传输的吧。
校验和
TCP是端到端的传输,由发送方计算校验和,接收方进行验证,目的是为了验证TCP首部和数据在发送过程中没有任何改动,一旦发现校验和有差错,直接丢弃TCP段并重新发送。
序列号/确认应答
TCP传输时发送方对每一个发送的消息都会编号,也就是序列号seq。接收方在每次接收到消息后回复确认应答号ACK,不仅告诉接收到哪些数据,还包括下一次消息从哪里发送。只要发送方没有接收到确认应答号ACK,都会重新发送数据。
超时重传
发送方发送完数据后会等待一定的时间,如果在这个时间内没有接收到ACK,就会重传数据。如果是发送方发生了丢包,那么接收方在接收到数据后会回复ACK,如果是接收方回复的ACK丢失了导致的重传,那么根据校验和和序列号知道该数据已经接收,丢弃该数据并发送ACK。
连接管理
三次握手和四次挥手。
流量控制(滑动窗口控制)
发送方发送数据的快慢取决于接收方接收能力。TCP的报文信息中有一个16位字段来标识滑动窗口,窗口大小就是接收方剩余缓冲区大小,在回复ACK时,接收方将自己剩余缓冲区大小填入。发送方根据窗口大小来调整自己的发送速度,如果缓冲区大小为0,那么发送方会停止发送数据。并且发送方定期会发送探测报文,来获取缓冲区大小。
快速重传
当接收端收到比期望号大的seq时候,就会发送冗余ACK,在超时重传之前如果收到三个相同的冗余ACK,那么就知道哪段报文发生了丢包,重传该段报文即可,避免了超时重传。
拥塞控制
网络可能刚开始很拥塞,如果在网络传输过程中开始就发送大量数据的话,会发生丢包和超时重传,所以需要慢启动算法、拥塞避免算法、快速重传和快速恢复。
慢启动算法
一开始不发送大量数据,而是应该先发一小部分探测数据,然后由小到大逐渐增大发送窗口。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为1,每次接收到报文之后将窗口大小翻倍。如果指数增长到避免拥塞算法的门限ssthresh,则改用避免拥塞算法。
- 初始化设置 cwnd = 1,并开始传输数据
- 收到回馈的 ACK,会将 cwnd 加 1
- 当发送端一个 RTT 后且未发现有丢包重传,就会将 cwnd = cwnd * 2
- 当 cwnd >= ssthresh 或发生丢包重传时慢启动结束,进入拥塞避免状态
避免拥塞算法
每当收到一个 ACK 时,cwnd 增加 1/cwnd,变为线性增长。一但发现丢包和超时重传,就进入拥塞处理状态。
拥塞发生
当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:超时重传和快速重传。
ssthresh 和 cwnd 的值会发生变化
- ssthresh 设为 cwnd/2
- cwnd 重置为 1
发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:
- cwnd = cwnd/2 ,也就是设置为原来的一半
- ssthresh = cwnd
- 进入快速恢复算法
快速恢复
- 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了)
- 重传丢失的数据包
- 如果再收到重复的 ACK,那么 cwnd 增加 1
- 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态
具体详细内容请见https://blog.****.net/qq_45444343/article/details/145670595?spm=1001.2014.3001.5501