【来源】:http://www.meilei007.cn/tcp_three_handshake_reason/
看了一些网上的解答,都不是很清楚,这里说一下我的理解。
首先说明为什么不能是两次握手,因为三次握手能够防止已过期的数据报被再次传到被连接主机。
举个例子,假设只需要两次握手连接就能够建立,那么客户端A往服务器端B发送连接数据报SYN,服务器端B没有收到该数据报,A又发送了第二个数据报SYN到B,B这次正常收到,返回ACK,A收到ACK,连接建立。数据传输完,连接断掉了之后,第一次发送的数据报SYN突然又到达了B,B会认为这是A发送的新的一次连接请求,返回一个ACK给A,这个时候,B认为连接建立,但是A收到一个莫名的ACK数据报,不会做任何处理。B就一直等在那里,等着A发送数据。
还有一种情况是两次握手可能发生的,举个例子,A发送给B大量的连接请求,B收到了,回复ACK的时候A却没收到,但是B不管,B认为已经建链成功了,开始往A发数据,但是A没有收到ACK,认为链接没建立,就会无视B的数据,一直等ACK,这样,就形成了死锁,B因为收不到A返回的数据ACK,会一直不断重发数据,A收不到B的建链ACK,会一直等待不接受数据。
那为什么不是四次握手呢?这里是因为服务器端在回ACK消息的时候,在同一个数据报里面,加上了自己的SYN数据,所以把这两个数据装在了同一个数据报里面。
那么在拆链的时候为何必须是四次呢?
这里要弄明白一点,TCP的数据传输是全双工的,单方面拆链并不影响对方向自己发送数据。因此,A发送FIN包给对方,表示我这边没有数据了,对方再回复ACK,表示不会再接受A发来的数据。B再发FIN包给A,A回ACK表示,“ok,我知道你也没数据发送了,我们连接关闭吧”。至此,TCP才是在两边真正断掉。当然,如果A发送FIN包给B,告诉B,我这边没数据的同时,B也没有数据发送了,那么B其实是可以在一个数据包里面把ACK和FIN包都发给A的,这样,其实三次也能把链接关掉。只不过传统的协议都是按照四次来实现的,就当做一个美好的传统来看待就好了,至少程序员写协议栈的时候更轻松了:)
三次握手建链:
四次握手拆链: