解析TCP连接之“三次握手”和“四次挥手”

葡萄美酒夜光杯,欲饮琵琶马上催。
醉卧沙场君莫笑,古来征战几人回?----唐 · 王翰 · 《凉州词》

前言

不管是面试别人还是被别人面试,有很大的可能会被问到TCP的“三次握手”,但是基本都可以回答上来,这部分内容理解起来并不是很难,我这篇文章主要是从TCP报文的角度解析TCP连接的“三次握手”和“四次挥手”,如果你也对这方面的知识感兴趣,可以按照下面的步骤进行抓包测试的。

准备工具:

  • sokit软件,作为TCP Client,用来连接TCP Server,也可以自己写代码实现这部分功能。
  • Wireshark软件,用来抓包的。

关于TCP的这些事:

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

使用Wireshark进行抓包,添加过滤器 “tcp”
在这里插入图片描述
截取抓包结果:
在这里插入图片描述从上面可以看出来,里面有9个字段:Source PortDestination PortSequence numberAcknowledgment numberFlagsWindow size valueChecksumUrgent pointersOptions

  • Source Port:源端口,16位
  • Destination Port:目的端口,16位
  • Sequence number:发送数据包中的第一个字节的序列号,32位。用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
  • Acknowledgment number:确认序列号,32位。只有ACK标志位为1时,确认序号字段才有效,Ack=Seq序列号+1。
  • Flags:标志位,共6个,即URG、ACK、PSH、RST、SYN、FIN
标志位 作用
URG 表示Urgent Pointer字段有意义
ACK 表示Acknowledgment number字段有意义
PSH 表示Push功能,接收方应该尽快将这个报文交给应用层
RST 表示复位TCP连接
SYN 表示SYN报文(在建立TCP连接的时候使用),发起一个新连接
FIN 表示没有数据需要发送了(在关闭TCP连接的时候使用),释放一个连接
  • Window size value:表示接收缓冲区的空闲空间,16位,用来告诉TCP连接对端自己能够接收的最大数据长度。
  • Checksum:校验和,16位。
  • Urgent pointers:紧急指针,16位。只有URG标志位被设置时该字段才有意义,表示紧急数据相对序列号(Sequence Number字段的值)的偏移。
  • Options:选项,32位。属于可变部分。

将上面的字段整合成一张图,TCP报文格式:
在这里插入图片描述图片来自:TCP报文格式简介

三次握手过程

举栗子:使用sokit连接TCP Server(IP地址:192.168.0.206,端口:1024),本机IP地址:192.168.0.62,端口:59420。

  • 运行Wireshark,添加过滤器 tcp && ip.addr == 192.168.0.206,应用于以太网2:
    在这里插入图片描述

  • 打开sokit,选择客户端模式,输入TCP Server的IP地址和端口,然后进行TCP连接:
    在这里插入图片描述

  • 当TCP连接成功建立后,Wireshark已经抓包成功了,结果如下:
    在这里插入图片描述
    分析:主机(IP地址:192.168.0.62,端口:59420)主动向TCP Server端(IP地址:192.168.0.206,端口:1024)发送 [SYN标志] 序列号Seq=0 报文,表示主机想建立连接,这是“第一次握手”。然后此时TCP Server端(IP地址:192.168.0.206,端口:1024)回给主机(IP地址:192.168.0.62,端口:59420)一条[SYN标志,ACK标志] 序列号Seq=0,确认号Ack=1(“第一次握手”中主机序号Seq的值+1)报文,表示TCP Server端确认了主机端发送过来的连接请求,这是“第二次握手”。最后主机回给TCP Server端一条[ACK标志] 序列号Seq=1,确认号Ack=1报文,其中主机序号Seq=1(“第二次握手”中TCP Server端确认号Ack的值),确认号Ack=1(“第二次握手”中TCP Server端序号Seq的值+1),表示主机已经收到了TCP Server端发送给它的确认请求,这是“第三次握手”。 至此,双方TCP连接建立成功,可以进行数据收发了。

将上面“三次握手”过程整合成一张图:

在这里插入图片描述
看到这里,为什么要三次握手呢?不可以是二次握手,或者是四次、五次握手吗?

如果只有两次握手就建立好连接,那这样很容易就浪费掉服务端的资源,当主机客户端第一次握手,发送SYN给服务端请求连接,然后服务端回给主机客户端SYN&ACK确认连接请求,进行第二次握手,但是此时,由于某些原因导致主机客户端收不到这条确认连接请求的报文,所以主机客户端会一直等待这条报文,但是主机客户端这边会设置连接超时时间,超过这个时间就会自动关闭连接创建的请求,再重新发出创建连接的请求,但是呢,服务端是完全不知道的,之前占用的资源没有释放掉,等收到主机客户端再次发出新的的连接请求后,又重新开辟新的资源进行处理,如此一来,随着每次的不断请求,服务端的资源也会不断的消耗。
至于为什么不是四次、五次握手,我觉得三次握手就可以确定好双方的通讯状态,建立连接了,四次五次就没有必要啦,就好比花一百块就能买到的iPhone,为啥还要花三四百呢?

四次挥手过程

接着上面的步骤,在sokit软件上断开TCP连接,将“TCP连接”按钮点掉就可以断开连接了,此时Wireshark也已经成功抓包,截图如下:
在这里插入图片描述
分析:主机(IP地址:192.168.0.62,端口:59420)主动向TCP Server端(IP地址:192.168.0.206,端口:1024)发送 [FIN标志, ACK标志] 序列号Seq=1, 确认号Ack=1 报文,表示主机想断开连接,这是“第一次挥手”。TCP Server端回给主机[ACK标志] 序列号Seq=1, 确认号Ack=2(“第一次挥手”中主机序号Seq的值+1)报文,表示TCP Server端已经确认了主机想断开连接的请求,这是“第二次挥手”。但是TCP Server端又发了一条[FIN标志, ACK标志] 序列号Seq=1, 确认号Ack=2报文给主机,表示TCP Server端已经准备好释放连接了,这是“第三次挥手”。最后主机回给TCP Server端一条[ACK标志] 序列号Seq=2, 确认号Ack=2报文,其中主机序号Seq=2(“第三次挥手”中TCP Server端序确认号Ack值),确认号Ack=2(“第三次挥手”中TCP Server端序号Seq的值+1)),表示主机确认了TCP Server端已做好释放连接的准备,这是“第四次挥手”。 至此,双方连接断开。

将上面“四次挥手”过程整合成一张图:

在这里插入图片描述
为什么需要“挥手四次”呢?

因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次"挥手"传输的。释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。

需要注意的是,主机在TIME WAIT阶段要等2MSL,为的是确认服务器端是否收到客户端发出的ACK确认报文。

非常感谢你能看到最后,如果能够帮助到你,是我的荣幸!

参考文章:

详解TCP连接的“三次握手”与“四次挥手”(上)

猜你喜欢

转载自blog.csdn.net/qq_36270361/article/details/108428803