TCP握手和挥手

1. TCP 连接建立与释放

TCP握手和挥手_第1张图片

2. 为什么要三次握手?

第一次握手: 

       客户端先发送一个 SYN 请求(SYN=1 表示该报文是一个连接请求报文),发送的序号 seq=x(x 是系统自己选定的大小),SYN 虽然不携带数据但是会消耗一个序列号。当客户端的 SYN 请求发送出去之后,客户端进入 SYN-SENT 状态。 

第二次握手: 

       服务器端收到客户端的连接请求报文,如果同意连接的话就像客户端发送一个确认报文。此确认报文的 SYN 和 ACK 的标志位都置为 1,确认号 a = x +1,同时服务器这边也要给自己设定一个发送序号 y。此报文同样不能携带数据,但也要消耗一个序列号。 

第三次握手: 

       客户端收到服务器端确认报文后,要再次向服务器端发送一个确认报文,表明我已经收到你的确认消息。此确认报文的首部 ACK 标志为 1,确认号 ACK= y+1,序号为 x+1。从此报文开始,就已经开始携带数据了,若此报文不携带数据则下个报文的序号认为 x+1。此后,客户端就进入了 ESTABLISHED 状态。

目的:防止已失效的连接请求又传到了服务器端。 

       场景(A为客户,B为服务器):A 向 B 发送一个请求连接报文,但是这个报文在网络中阻塞了,并没有传到 B。所以 B 也无法向 A 发送确认报文,在 A 的重传计时器到达之后,A 再次向 B 发送请求连接报文,这个报文 B 收到了,并且向 A 做出应答,建立连接,传输数据。数据传输完后,关闭连接。问题来了,就在 B关闭连接之后,A 第一次发送的请求连接报文到了(这个报文是已经失效的),B 以为 A 要再次创建一个新连接,于是向 A 发送确认报文。 

       如果采用两次握手的话,此时连接已经建立了。但是 A 根本没有向 B 发送请求连接报文,所以 A 并不会理会 B 的确认。B 以为此时连接已经建立了,就会一直等待 A 向它发送数据。这样 B 的资源就白白浪费了。 但是采用三次握手就不同了,A 不会因为 B 的确认而向 B 发送确认,B 收不到 A 的确认,就知道 B 没有请求连接。B 的资源也就不会浪费。


3. 为什么要四次挥手?

       在 TCP 连接的时候 ACK 和 SYN 是一起发送的,断开连接的时候却没有一起发送。原因是:TCP 是全双工的,接收到 FIN 意味着不会收到数据,但是却还可以发送数据。在建立连接的时候服务器可以把 SYN 和 ACK 放在一个包中进行发送。 关闭连接的时候,一端收到 FIN 包此时还有数据没有发送完,就要向对方回复 FIN 包的ACK。将数据发送完之后再向对方发送 FIN,所以分开发送。 因为是各自互相发送 FIN 报文,以及发送对对方 FIN 报文的确认报文,所以要进行四次挥手。

第一次挥手: 

       数据传输完成后要释放连接的时候,客户端的上层应用会向客户端发送连接释放的报文。并停止发送数据主动的关闭连接。客户端会向服务器发送连接释放的报文,报文的首部终止位 FIN 的值为 1,之后客户端的进入 FIN-WAIT-1 的状态。 

第二次挥手: 

       服务器端对客户端的终止终止请求报文进行应答并确认服务器端报文段的序号,发送完之后服务器端进入 CLOSE-WAIT 状态。此时连接处于半连接的状态,客户端已经没有向服务器端要发送的数据了,但是此时服务器端还可以向客户端发送数据。 

第三次挥手: 

       如果服务器端没有向客户端再发送的数据,则服务器端的应用进程就会释放 TCP 连接。服务器端也会向客户端发送终止请求报文,发送完成之后服务器端就进入 LAST-ACK状态。(最后确认状态) 
系统的实现不同,在 Linux 上一般经过半分钟后就可以再次启动 server 了。

第四次挥手: 

       客户端在收到服务器端的连接释放报文之后,再次向服务器端发送确认报文。是对第三次挥手的应答,此后客户端进入 TIME-WAIT 状态。客户端在发送确认报文之后不会立即结束,而是等待 2MSL 之后才会结束。 MSL:最大报文段寿命。 服务器端在收到客户端的确认报文之后就结束了此次连接进入 closed 状态。


4. 主动断开链接的一方为什么要进入 TIME_WAIT 状态?

(1)有下述两个原因: 若在第四次挥手时发出ACK确认应答时,由于网络原因导致ACK 确认应答的 报文没有被被动方收到,等到2MSL从而触发被动方重新发送FIN包, 因而主动关闭连接的一方需要停留在 TIME_WAIT 等待状态以处理对方重新发送的FIN数据包。否则它会回应一个RST数据包给被动关闭连接的一方,引起被动方关闭流程错乱。 
(2)在TIME_WAIT状态下,是不允许应用程序在当前ip和端口上与之前通信的client(这个client的ip和端口号不变)建立一个新的连接的。这样就能避免新连接收到之前的连接(ip和端口一致的连接)残存在网络中的数据包了。这也是TIME_WAIT状态的等待时间被设置为2MSL的原因,以确保当前网络两个连接方向上的尚未接收到的TCP报文已经全部消失 。

你可能感兴趣的:(TCP握手和挥手)