网络间的一次连接(tcp,面向连接的,不讲udp)是以三次握手开始,四次挥手结束的,本文讲解一些三次挥手以及四次挥手的概念以及抓包情况
一次完整的连接
一次连接的整体抓包情况大致如下:
No. Time Source Destination Protocol Length Info
267 2.085279 127.0.0.1 127.0.0.1 TCP 56 52363 → 1080 [SYN] Seq=0 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
268 2.085360 127.0.0.1 127.0.0.1 TCP 56 1080 → 52363 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
269 2.085486 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [ACK] Seq=1 Ack=1 Win=2619648 Len=0
270 2.085732 127.0.0.1 127.0.0.1 Socks 143 Unknown
271 2.085778 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [ACK] Seq=1 Ack=100 Win=2619648 Len=0
290 2.089224 127.0.0.1 127.0.0.1 Socks 83 Unknown
291 2.089284 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [ACK] Seq=100 Ack=40 Win=2619648 Len=0
292 2.090078 127.0.0.1 127.0.0.1 Socks 561 Unknown
293 2.090137 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [ACK] Seq=40 Ack=617 Win=2619136 Len=0
884 7.091029 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [FIN, ACK] Seq=40 Ack=617 Win=2619136 Len=0
885 7.091057 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [ACK] Seq=617 Ack=41 Win=2619648 Len=0
886 7.091262 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [FIN, ACK] Seq=617 Ack=41 Win=2619648 Len=0
887 7.091287 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [ACK] Seq=41 Ack=618 Win=2619136 Len=0
完整的一次连接流程图如下:
三次握手
第一次握手:
客户端发起连接SYN消息,并且变成SYN_SENT状态
第二次握手:
服务端接受到客户端发来的SYN消息,发送SYN加ACK消息,并且变成SYN_RCVD状态
第三次握手:
客户端收到服务端发来的SYN+ACK消息,变成ESTABLISHED状态,并且客户端发送ACK消息给服务端
服务端收到客户端发来的ACK消息,变成ESTABLISHED状态,这样一个连接就建立好了
三次握手对应的抓包数据如下:
No. Time Source Destination Protocol Length Info
267 2.085279 127.0.0.1 127.0.0.1 TCP 56 52363 → 1080 [SYN] Seq=0 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
268 2.085360 127.0.0.1 127.0.0.1 TCP 56 1080 → 52363 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
269 2.085486 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [ACK] Seq=1 Ack=1 Win=2619648 Len=0
四次挥手
第一次挥手
客户端发送FIN消息告诉服务端 我这边数据传输完了,准备断开连接了,并且进入FIN_WAIT_1状态
第二次挥手
服务端收到客户端的FIN消息,返回ACK消息表示自己知道了,进入CLOASE_WAIT状态,但是服务端可能还有数据没有处理完
客户端收到服务端的ACK消息之后 进入FIN_WAIT_1状态
第三次挥手
服务端也处理完所有数据之后,向客户端发送FIN消息,表示自己数据也处理完了,准备断掉连接,并进入LAST_ACK状态
第四次挥手
客户端收到服务端的FIN消息,返回ACK表示确认,自己进入TIME_WAIT,过一段时间进入CLOSE状态
服务端收到客户端发来的ACK消息后,也进入CLOSE状态
四次挥手抓包数据如下:
884 7.091029 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [FIN, ACK] Seq=40 Ack=617 Win=2619136 Len=0
885 7.091057 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [ACK] Seq=617 Ack=41 Win=2619648 Len=0
886 7.091262 127.0.0.1 127.0.0.1 TCP 44 52363 → 1080 [FIN, ACK] Seq=617 Ack=41 Win=2619648 Len=0
887 7.091287 127.0.0.1 127.0.0.1 TCP 44 1080 → 52363 [ACK] Seq=41 Ack=618 Win=2619136 Len=0
知识点
【1】三次握手的原因
因为连接的建立是全双工的,也就是客户端和服务端两边都要完成建立,所以三次是最少的,多了就是浪费
【2】四次挥手的原因
因为数据交互是客户端和服务端两端进行的,端口需要两方都要确认才能断开,一段准备断开连接,不代表另一端的数据传输完了,需要等另一端也发出关闭连接的消息,不然就会出现问题
【3】也可能是三次挥手
如果服务端收到客户端的FIN请求的时候,自己的数据也处理完了,那么确认ACK消息以及自己的断开连接FIN消息可以在一个包进行发送,这个时候就变成了三次挥手
【4】四次挥手,为什么最先发起端最后要等一段时间变成CLOSE状态
为什么最先发起断开连接的一段 最后收到对方的FIN消息并发出ACK消息之后不是立马变成CLOSE状态,而是要等一会
这是因为,如果客户端最后哦发送的ACK消息因为一些原因,服务端没有收到,那么服务端就不会关闭这个连接,并会重试发送之前的FIN包,而这个时候,如果客户端已经断开了之前这个连接,并用之前连接对应的端口新建了一个新连接,那么这个新连接收到FIN包可能就会以为是关闭连接请求,将不该关闭的新连接给关闭了
所以,最先发起断开连接的一端,再发出最后一个ACK消息之后,要等2 MSL的时间才会变成CLOSE状态(MSL为一段报文从一段到一段的最大时间,也称为报文的最大生存时间)