TCP三次握手和四次挥手详解
TCP工作在传输层,每一次连接都需要三个阶段:建立连接,数据传送和数据释放。"三次握手"就发生在连接建立阶段。
目的是防止已失效的连接请求报文段突然又传送到了服务端,因而发生错误。
"已失效的连接请求报文段"的产生在这样一种情况下:
(客户端)client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但(服务端)server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。若不采用"三次握手",那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用"三次握手"的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。"
三次握手是指建立一个TCP连接时,需要客户端和服务端总共发送3个包。
首先client发送连接请求报文,SYN=1 ACK=0 (请看文首TCP包头的介绍),TCP规定SYN=1时不能携带数据,但要消耗一个序列号,因此声明自己的序号是seq=x
然后server段接受连接后回复ACK报文,并为这次连接分配资源,client端接收到ACK报文后也向server段发送ACK报文,但不用SYN了,这时即为ACK=1,seq=x+1,ack=y+1
并分配资源,这样TCP连接就建立了。
然后就是断开连接了,TCP的连接的拆除需要发送四个包,因此称为四次挥手。
客户端或服务端均可发起挥手动作,在socket编程中,任何一方执行close操作即可产生挥手操作。
简单的过程如下:
假设客户端A发起中断连接请求,也就是发送FIN报文,服务器端接受到FIN报文后,意思是说"我客户端没有数据发送给你了",但是如果你还有数据没有发送完成,就不必急着关闭socket,可以继续发送数据,所以你先发送ACK,"告诉客户端,你的请求我收到了,请你继续等我的消息"这时候客户端就进入FIN_WAIT状态,继续等待服务端的FIN的报文,当服务端确定数据已经发送完成,则向客户端发送FIN报文"告诉客户端,好了,我这边数据发完了,准备好关闭连接了"客户端收到FIN报文后,"就知道可以关闭连接了,但它为了保险起见,担心服务端不知道要关闭,所以发送ACK后进入T"TIME_WAIT状态,如果服务端没有收到ACK可以重传。"服务端收到ACK后,"就知道是时候断开连接了。"客户端等待了2MSL后没有收到回复,则说明服务端已正常已正常关闭,接着,客户端也可以关闭连接了,到此TCP的连接都关闭了。
【注意】 在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
娱乐一下:我老家开往北京的大巴,由于没有车站买票,所以采用直接给大巴司机打电话预定的方式订票。 而大巴司机的智慧简直让我惊叹劳动人民的伟大。 订票流程是这样子的,我们前一天上午先给司机打电话订票,司机前一天下午打电话向每一个人确认。第二天坐车的时候凭借电话号码上车。这就是活生生的三次握手。