TCP与三次握手

qc1iu published this page · Last modified:

TCP是在不可靠的网络层上提供可靠的传输服务。如何理解?假设你拥有一个快递公司,但是快递小哥不是很靠谱, 送货偶尔会出问题,所以你经常收到投诉电话,处理一些复杂的问题。比如有些快递压舱了,有些丢失了,有些损坏了等等。为了解决这个问题,你雇佣了一个经理人,全权负责这些琐事。这个经理就相当于TCP的功能。而快递小哥就是不靠谱的网络层。网络层的不可靠是指数据不一定会在规定的时间内按照规定的顺序到达。比如快递丢了,这就是直接没送到,或者快递在中间某一个站点滞留了很久很久,最终可能会送到,但是很不幸你包裹是水果,送到都烂掉了。而我们通常所说的TCP是可靠的,指的是TCP通过了一些手段,使得传输看起来可靠。这个与 视觉暂留的效果类似,都是对上层提供的一种假象。那么哪些手段可以用来保证可靠?

重传

重传是TCP保证可靠的唯一方式。这个道理没法在解释了。一个数据在网络中丢了也好,蒸发了也好,想要对面收到,恐怕除了重新发一个一模一样的数据没有其他的方法。但这里的问题是,发送方在什么情况下重传。

我们把问题简化,假设现在没有TCP(假设现在是1975年),网络中只有发送方A和接收方B,A和B一生只通信一次,一次只发送一个数据包,只能A发送数据,B接收数据,在一个不可靠的信道上,A如何确定B收到了数据?

应答

应答(ACK)是判断是否重传的指标。现在我们允许B发送数据,不过只能发送ACK。当发送方收到ACK则认为数据可靠抵达,在一段时间内没有收到就可以重新发送。这样,拥有了重传和应答两项技能,我们就保证了通信双方在只发送一个数据包的情况下的可靠通信。强调一下,这里的可靠是指,只要收到了ACK则数据一定被B收到,但是并不保证一定会收到ACK,而且没有收到ACK数据也未必没有到达。说以A收到ACK是B收到数据包的充分条件,而不是必要条件。

我们现在再提一些需求。假设现在没有TCP(假设现在是1975年),网络中只有发送方A和接收方B,A和B一生只通信一次,一次发送多个数据包,只能A发送数据,B接收数据(可发送ACK),在一个不可靠的信道上,A如何确定B收到了所有的数据?假设B知道A到底发送了几个数据包,那么B可以在收到所有数据包后给一个ACK。但是,实际情况是B并不能知道A到底发送了几个数据包,所以只能收到一个确认一个。如此一来,A即使收到了ACK,也不知道到底B确认的是哪个数据包。

序号

如果能使得ACK能标明确认的到底是哪个数据包,那问题看起来就解决了。所以我们就在A发送数据包时给数据包一个编号。这样A发送了n个数据包,就等着接收n个对应ACK。而B也不需要知道A到底发送了多少数据包,只需要确认当前收到的数据包就可以。我们暂定这个标号从0开始。

我们现在再提一些需求。假设现在没有TCP(假设现在是1975年),网络中只有发送方A和接收方B,A和B可以通信多次,一次发送多个数据包,只能A发送数据,B接收数据(可发送ACK),在一个不可靠的信道上,A如何确定B收到了所有的数据?在拥有重传,应答,序号等功能后,我们实现了在不可靠信道上单方向通信一次多包的可靠传输。在通信多次的情况下,多次通信的数据包的确认信息会出现相互干扰,在某一时刻信道中可能存在多个编号为x的包。即使我们在一次通信结束之后再开始第二次通信,由于网络的堵塞和发送方的重传机制,在某一时刻信道中可能还是会有若干编号相同的包。

我们假设包的编号可以无穷大。如果每次通信能使用不同的编号区间,貌似就解决了这个问题。要做到这样,在每次通信过程真正开始之前,发送方与接收方需要协商一个起始编号。

二次握手-四次握手-三次握手

协商编号的过程,就是让接收方B知晓发送方A发送的数据包的起始标号。所以还是一个数据包的可靠传输问题,我们之前已经解释过,拥有重传,应答两项技能就可以保证一个包传输的可靠性。所以这个协商过程就是指的双方一问一答(看上去是一问一答,实际上由于信道的不可靠,可能尝试多次才完成一问一答),也可以称为二次握手。

我们之前一直假设只有A向B发送数据,B只能响应ACK。如果双方都可以向对方发送数据,那么不仅A要让B知道自己的起始编号,B也要让A知道自己的起始编号。于是需要四次握手。在这个过程中,B的应答和请求可以合并到一起,于是变成了三次握手。

结论

TCP保证可靠的方式是重传。三次握手建立可靠链接的说法其实是不恰当的。在实际情况中,数据包的编号不可能无穷大,也会出现重复的问题,不过这又是另外一个单独的问题,RFC1323中定义的PAWS对这个问题有更详细的描述,感兴趣的可以参考。