TCP建立连接为什么是三次握手?

              我们都知道TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP也是日常通讯中用的最广泛的一种协议,TCP的连接需要三次握手,断开连接需要四次挥手,那么TCP的连接过程为什么是三次握手而不是两次或者四次呢?

    根据《UNIX网络编程》所述的TCP状态转换变迁图所示:

TCP建立连接为什么是三次握手?_第1张图片   

  从状态转换图我们可以看出TCP的连接建立经历了 SYN----SYN+ACK-----ACK的过程, 也是常称之为三次握手的过程,如下所示:

第一次握手:建立连接时,主动连接的一方(通常时客户端)发送syn包到被动链接的的一方(通常是出于LISTEN的服务器),syn包有初始交互的序列号,如sny=j。发送完成后客户端进入SYN_SENT状态,等待服务器响应确认。

第二次握手:被动连接的一方,主要是服务器,收到客户端发来的syn包,必须确认客户的syn(ack=j+1), 同时自己也要发送syn包(syn=k),目的在于告诉对方自己的初始化同步序列号。发送syn+ack包,发送完成后服务器进入SYN_RECV状态,等待客户端对该syn的确认。

第三次握手:客户端收到服务器的syn+ack包后,恢复ack=k+1的ACK包回复服务器,来告知服务器收到同步序列号。发送完成客户端进入ESTABLISHED状态,表明TCP状态建立完成。当最后的这个ack包服务端收到后,服务端也进入ESTABLISHED状态,等待客户端正式数据的到来。如果该ack没有收到,在特定时间后服务器将重新发送第二步中的syn+ack包,直到收到ack确认或者连接超时放弃连接。如下图所示:

TCP建立连接为什么是三次握手?_第2张图片


在三次握手的协议中,对于服务器来讲需要维护一个未连接队列。该队列为所有收到syn包都开一个条目,表示服务器已经收到了来自客户的syn包,已经自动完成了syn+ack的回复,正在等待新的ack包到来,从而确定连接建立成功。这些队列里的所有条目对应的连接都是服务器处于SYN_RECV状态,当客户的确认ack包收到时,从队列中删除该连接对应的条目。与此同时该连接状态也变更为ESTABLISHED,如若一直未收到ack的最后确认,当条目在队列的保持时间超过了半连接的最大存活时间或者对没有收到ack确认的连接的超市重传syn+ack包次数超过系统指定次数,都将此半连接对应的条目从队列删除。需要注意的是该未连接队列是有大小限制的,当队列已满时新到的syn包都将无法进行处理。


     那么问题来了, TCP为什么需要三次握手?

     在谢希仁著《计算机网络》中讲到三次握手的目的是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。也就是说为了解决网络中存在延迟的重复分组的问题。具体来讲就是说,假设我们是两次握手建立TCP连接,当网络中有个客户端的syn因为某种原因而滞留了,当这个丢失的分组在连接关闭后到达了服务器会怎么样? 服务器认为是新的请求连接到来,回复了ack确认,同时进入了ESTABLISHED状态,而这个ack包到达客户端却无法正常处理。此时就陷入了不好情况。

    三次握手的本质原因是因为我们通讯所处的通讯链路和信道是不可靠的,但是我们的通讯和数据传输需要的是可靠的信息流动,就像我们打电话一样,不能我说了一句话那边只听到半句或者听不到,我在等对方回答,对方却在等待我的问题,这就进入了死锁的状态是不是很尴尬。通讯双方为了解决这种不可靠,无论消息中包含什么信息,在数学归纳法来讲,三次通讯是理论上的最小值,所以才有了三次握手。简单讲,三次握手不是TCP的问题,也不是TCP所需要的必须条件,而是为了满足在不可靠的链路信道上进行可靠地消息传输这个问题需求所导致的。链路信道不可靠,而需要数据传输可靠,三次达到了,也就解决了信道不可靠的问题。后面不管你交互任何信息就和进行可靠的信息传输需求就没关系了。因为你信道可靠了无论你发送什么消息,什么时候发送,只要连接在,对方都一定能收的到。这就导致了三次是信息可靠发送的基础,试想如果你不需要打电话 只是需要寄一张贺卡,对方收不收得到你完全不关心,那就像UDP一样去直接发送就好了,根本也不需要建立什么三次握手,信道可不可靠对他来说都是一样的。

你可能感兴趣的:(TCP/IP)