TCP通信的可靠性

如何确定包已被对方接受

Posted by mengxun on November 25, 2018

建立连接

TCP建立连接的方式就是三次握手,而三次握手的意义主要就在于通信双方确定一个初始的同步序列号(Seq),过程表示出来大概是:

SYN=1 Seq=client_isn
------------------------------------------->
SYN=1 ACK=1 Seq=server_isn Ack=client_isn+1
<-------------------------------------------
ACK=1 Seq=client_isn+1 Ack=server_isn+1
------------------------------------------->

其中的同步序列号就是可靠性的重要保证。那么如何通过同步序列号保证可靠性呢?

双方通信过程

三次握手之后开始进行通信的过程表示如下:

Seq=client_isn+1 Ack=server_isn+1 Len=n1
------------------------------->

Seq=server_isn+1 Ack=(client_isn+1)+n1 Len=n2
<------------------------------

Seq=(client_isn+1)+n1 Ack=(server_isn+1)+n2 Len=n3
------------------------------->
...

建立连接之后的双方通信会继续沿用三次握手所确立的同步序列号,并且Ack的值为接受的包的同步序列号加上Len的长度(Len的长度其实就是TCP的payload的字节数)。 这样凭借着三次握手确立的Seq和互相反馈的Ack就可以很清楚的知道对方有没有接受到包。 另外,为了保证可靠性,TCP协议还提供了重传机制,这样哪怕中间发生了丢包,只要没收到对方Ack,数据就不会从自己的发送缓冲区清除,就可以再次发送。

重传

TCP的重传分两种,一种是超时重传,一种是快速重传,超时重传就是超过了一定的时间没有收到对方的Ack就重传,快速重传就是当一方连续收到三次相同的Ack时就可以认为这个包丢了,就会重传。 不过这两种机制都有一个问题,就是无法知道到底只丢了一个包,还是除了这一个包之外后面的包还有丢的,这个问题可以通过在TCP头部加入SACK解决。