TCP 协议如何保证性能( 三 )


如果连接建立期间,客户端机器由于异常挂掉怎么办?
实际上 TCP 连接存在保活计时器,如果客户端机器发生故障,服务端肯定不会白白浪费资源死等下去 。每当服务端收到客户端消息都会刷新这个计时器,时间通常是两小时,如果两小时内服务端没有收到客户端的任何请求,服务端就会发送探测报文段,以后每隔75分钟发送一个探测报文段,如果一连十个探测报文段都没有回复,服务端认为客户端出现异常,主动断开连接 。
确认应答机制
对于内存较大的数据,一个报文肯定不足以完全传输,此时就需要分批次发送 。为了使客户端时刻了解服务端接受了哪些数据,TCP 采用确认应答的方式保证数据连续不丢失:
TCP 对每个字节的数据进行了编号,即序列号 。每个 ACK 都带有确认序列号,意思是告诉发送者:我已经收到了哪些数据,下一次你要开始从哪里发 。
超时重传机制
对于网络问题丢失的数据包,TCP 根据是否收到 ACK 确认数据包确定是否发送成功 。如果规定时间内没有收到确认数据包,就认为该数据包丢失,重新发送 。
上面我们列举了超时重传机制的一种,实际上包含两种情况:
然而对于由于网络问题滞留的数据包,就可能存在多发或者多答复的情况,在这种情况下,就可以根据序列号确认哪些消息有效、哪些消息无效,以此保证数据正常传输 。
每次发送数据包之后的超时等待时长是动态改变的:
我们需要根据不同的网络环境找到最小的确认应答能够返回的时间 。一般情况下,超时时长以 500ms 作为基本单位,每次发送数据后超时时长都以 500ms 的整数倍作为重传时间 。重传一次仍等不到回答后,就等待 2 * 500ms 的等待时长,如果仍得不到回答就等待 4 * 500ms 的等待时长,以此类推 。当等待时长达到最大界限后,TCP 认为网络或接收端出现异常,强制断开连接 。
TCP 协议如何保证性能
上面我们简单介绍了 TCP 如何保证可靠性,下面我们来简单整理一下它如何保证高性能:
滑动窗口
前面整理关于 TCP 如何保证可靠性时,我们提到了确认应答机制:即对于每个数据包,都需要收到它对应的确认数据包后才继续向下发送 。这种做法虽然可以保证数据的完整性以及安全性,但是很影响性能:每个数据包必须等到前一个数据包发送并确定完毕后才能发送,如果整体网络环境较差,每次确定时间较长,那么排在后面的数据包将耗费大量的时间等待 。
为了解决这个问题,TCP 提出了窗口的概念:每次发送多个数据包,发送完毕后等待接收方确定,根据接受方返回结果确定下次发送的数据包 。窗口在这里就表示无需等待确定,可以直接发送的数据包的最大值 。
举个例子:假设每个数据包最多包含1000字节的数据 。发送4000字节的数据时就需要发送4次 。假如此时窗口的大小为4000,那么就需要直接发送这四个数据包,无需依次等待确定 。
如上图所示,当使用大小为4000的窗口时,每次可以发送4个数据包,等收到接受端确定后,根据接收端返回结果发送新的数据包 。
如上图所示,每次收到确认号后,窗口向右滑动,因此有时也称滑动窗口 。操作系统内核为了维护窗口的滑动,需要开辟发送缓冲区来记录当前还有哪些数据没有应答 。只有收到 ACK 确认过的数据才能从缓冲区中清除 。
使用滑动窗口发送数据过程中,有可能存在数据包丢失的情况,一般情况下有这两种情况:
发送过程中丢失:
当某一个数据包丢失后,接收方会一直返回相同的 ACK 提醒发送方自己需要哪些数据 。当客户端收到3个相同的确认号后,则重新发送丢失的数据包 。这种重传机制也被称为高速重发机制 。