浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第13章 TCP编程(2)_TCP的连接和关闭过程

Posted on 2017-04-04 22:47  浅墨浓香  阅读(507)  评论(0编辑  收藏  举报

4. TCP的连接和关闭过程

 

4.1 TCP连接的三次握手和四次挥手

(1)三次握手

  ①第1次握手建立连接。客户端发送连接请求报文段(SYN=1,sequence Number=x);然后客户端进入SYN_SEND状态,等待服务器确认

  ②第2次握手服务器收到SYN报文段,然后对SYN报文段进行确认,并设置(Acknowlegement Number为x+1)。同时,自己还要发送SYN请求信息。上述信息放到一个报文段(SYN+ACK)中,一并发送给客户端,此时服务器进入SYN_RECV状态

  ③第3次握手客户端收到服务器的SYN+ACK报文段。然后将ACK设置为y+1,向服务器发送ACK报文,这个报文段发送完以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP的三次握手。

(2)四次挥手

  ①第1次挥手客户端(也可以是服务端)设置seq和ACK,向服务器发送一个FIN报文段。此时,客户端进入FIN_WAIT_1状态,表示客户端没有数据要发送给服务器了

  ②第2次挥手服务器收到客户端发送的FIN报文段,向客户端回一个ACK报文,客户端收到后进入FIN_WAIT_2状态;表示服务端收到客户端的关闭请求,但服务端可能还有数据没发完,让客户端继续等服务端的通知

  ③第3次挥手服务器向客户端发送FIN报文表示服务端数据己发送完毕,可以关闭连接。同时服务器进入LAST_ACK状态

  ④第4次挥手客户端收到服务器发送的FIN报文向服务器发送ACK报文,然后客户端进入TIME_WAIT状态。服务器收到客户端的ACK报文段后,就关闭连接。此时,客户端等待2MSL后就关闭连接了。

4.2 为什么要三次握手

(1)可防止己失效的连接请求报文突然又传递到服务端

  ①假设Client发出第1个连接请求报文段并没有丢失而是在某个网络结点长时间滞留,以致延误到以后的某个时间才到达Server。但这时客户端己经因超时重发一个连接请求报文段给Server,并正常建立了连接。

  ②如果采用两次握手那么当这个延迟的连接请求到达时,服务端只需发送一个确认,新的连接就会在服务端建立起来。但客户端收到这个确认,它会认为自己并没有发出请求(因为该请求己失效!),因此就不会理会服务端的确认,也不会向服务端发送数据服务端则认为新的连接己经建立了,就一直等待客户端发送数据,直到超出保活计时器设置值才判断客户端出了问题,这样无形中就会浪费服务器的资源

  ③而如果采用3次握手,服务端收到延迟的连接请求(第1次握手)并向客户端发送确认,但客户端收到这个确认时(第2次握手),同样并不会理会它,因此也就不会与服务端进行第3次握手。由于采用三次握手机制这时服务端因没握过第3次手,所以并不会建立连接这样就可以解决失效请求突然到达的问题

(2)可靠性的理解

  ①世界上不存在完全可靠的通信协议。当A发送一个请求给B时,为了保证可靠性,B需要给A发一个己收到请求的确认包,但B的这个确认包是否到达A,需要A发送一个确认的确认给B,而这个确认B是否收到,仍需要B发给A一个确认,如此无休止去确认下去…。因此,从理论上无法做到完全的可靠,一般只需3次握手即可保证有较高的可靠性。

  ②“三次握手”是点对点通信的一般规则,但即使三次握手成功,也只能说明之前的通信条件和环境,而不能决定和预测之后的通信环境。根据经验,两个端点通信失败,最大的可能性是端点本身的故障,而三次握手成功排除了这种可能(见后面4.4中对讲机的例子。以后的情况很难预测。通信协议只能做到尽可能的可靠,而不能做到理论上的完全可靠

  ③由于TCP是面向连接的,无论哪一方向另一方发送数据,都必须在双方之间建立一个可靠的连接。

4.3 为什么需要4次挥手

(1)发起中断连接可以是客户端也可以是服务端。假设这里由客户端发起。当发送FIN报文时表示“我(Client)没有数据要发给你了”但如果你有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据

(2)服务端收到客户端的FIN报文后,先发送一个ACK用于告诉客户端“你的请求我收到了,但我还没准备好,请你继续等我的消息”。这时客户端进入FIN_WAIT_1状态,继续等待Server端的FIN报文。

(3)当服务端确定数据己发送完毕,则向Client端发送FIN报文告诉Client端,好了,我(Server)这边的数据己发送完结了,准备好关闭连接了

(4)客户端收到服务端的FIN报文后,就知道可以关闭连接了。但服务端并不知道客户端收到这个FIN报文没有,因此客户端要发送最后一个ACK报文,以便告知服务器己收到FIN如果服务器收到这个ACK,就可以关闭连接。但现在客户端并不急着马上关闭连接,因为最后一个ACK可能丢失,所以客户端要等2MSL(2倍的最大报文生存时间)的时间,如果这期间没有收到服务器的信息,说明服务器己经关闭,否则需重发最后的那个ACK报文。

4.4 生活中的例子

(1)对讲机的三次握手

  ①C→S“喂,你听得到吗?”(C ->SYN_SEND)

  ②S→C“听到,你听得到我吗?”(应答与请求同时发出,S->SYN_RCVD | C ->ESTABLISHED。注意:第2次握手能说明C的发和S的收都没问题)。

  ③C→S“能听到,今天balabala……”(S->ESTABLISHED。注意:第3次握手能说明C的收和S的发也没问题。到此TCP的双工模式被证明能正常工作!)

(2)四次挥手

  ①C→S“喂,我不说了。”(C→FIN_WAIT1)

  ②S→C“我知道了。等下,上一句还没说完。Balabala…..”(S→CLOSE_WAIT && C→FIN_WAIT2)

  ③S→C好了,说完了,我也不说了。”(S→LAST_ACK)

  ④C→S我知道了。” S关闭连接,C等待S收到了消息(时长:2MSL),如果这段时间S无回应,说明S己关闭。否则重说一次”我知道了”给S端。(C→TIME_WAIT && S→CLOSED,最后C→CLOSED)