目录
- 一、什么是 TCP 三次握手?
- 二、什么是 TCP 四次挥手?
- 三、Wireshark抓包验证
- 3.1 如何捕获三次握手、四次挥手
- 3.2 TCP 三次握手的记录
- 3.3 数据传输
- 3.4 TCP 四次挥手的记录
一、什么是 TCP 三次握手?
TCP
(Transmission Control Protocol,传输控制协议)的 三次握手
(Three-Way Handshake)是 TCP 连接建立的过程。在 TCP 中,连接的建立和关闭都是通过客户端和服务器之间的一系列握手完成的。三次握手用于确保客户端和服务器之间的连接是双向的,并且双方都能发送和接受数据。
三次握手的过程如下:
注意:图中,
seq
表示序列号;seq=x
中x表示在客户端序列号已经迭代到x了,如果是第一次请求,x就是0;seq=y
中y表示在服务端序列号已经迭代到y了,如果是第一次响应,y就是0。
- 第一次握手(同步请求):
- 客户端发送一个带有
SYN
(同步序列编号)标志的 TCP报文段给服务器,请求建立连接。这个报文段还包含一个初始序列号,用于后续的数据传输。 - 客户端进入
SYN_SENT
状态,等待服务器确认。
- 客户端发送一个带有
- 第二次握手(同步确认):
- 服务器收到客户端的
SYN
报文段后,如果同意建立连接,会回复一个SYN+ACK
(同步确认)报文段。这个报文段同样包含一个确认序列号,确认客户端的序列号,并提供自己的初始序列号。 - 服务器进入
SYN_RECEIVED
状态。
- 服务器收到客户端的
- 第三次握手(确认):
- 客户端收到服务器的
SYN+ACK
报文段后,会发送一个带有ACK
(确认)表示的报文段给服务器,确认服务器的序列号。 - 客户端和服务器都进入
ESTABLISHED
状态,此时连接完全建立,双方可以开始数据传输。
- 客户端收到服务器的
三次握手是 TCP 连接建立的必要步骤,它保证了在不可靠的网络环境中,TCP 能提供可靠的数据传输服务。
三次握手确保了以下几点:
- 客户端和服务器都能发送和接收数据。
- 双方都确认了对方的序列号,用于数据包的顺序恢复和重复检测。
- 连接是双向的,确保了数据的可靠传输。
二、什么是 TCP 四次挥手?
TCP 四次挥手
(Four-Way Wave)是TCP协议中终止一个已建立连接的过程。与三次握手用于建立连接类似,四次挥手用于在双方完成数据交换后,安全地关闭连接。四次挥手的过程 确保了所有数据都被正确传输,并且双方都同意关闭连接。
TCP四次挥手的过程如下:
- 第一次挥手(终止请求):
- 任意一方(通常是客户端)发送一个带有
FIN
(Finish)标识的 TCP 报文段,表示数据传输完毕,希望关闭连接。这个报文段也包含一个序列号。 - 发送
FIN
的一方进入FIN_WAIT_1
状态。
- 任意一方(通常是客户端)发送一个带有
- 第二次挥手(终止确认):
- 接受
FIN
的一方(通常是服务器)会发送一个带有ACK
(Acknowledgement)表示的报文段,确认接收到FIN
。这个ACK
报文段确认的是FIN
报文段的序列号。 - 发送
ACK
的一方进入CLOSE_WAIT
状态,而发送FIN
的一方收到ACK
后进入FIN_WAIT_2
状态。
- 接受
- 第三次挥手(终止请求确认):
- 当接收
FIN
的一方也完成了数据发送,它也会发送一个带有FIN
标志的报文段,表名自己也完成了数据发送,希望关闭连接。 - 发送
FIN
的一方进入LAST_ACK
状态。
- 当接收
- 第四次挥手(最终确认):
- 最初发送
FIN
的一方在收到第二个FIN
后,会发送一个ACK
报文段,确认接收到了对方的FIN
。 - 发送
ACK
的一方进入TIME_WAIT
状态,等待足够的时间以确保ACK
报文段到达对方。在此之后,连接正式关闭。
- 最初发送
TIME_WAIT
状态的存在是为了确保最后一个 ACK
报文段能够到达对方,防止在网络延迟或阻塞的情况下丢失。在 TIME_WAIT
状态保持一段时间后(通常是最大段生存时间MSL的两倍),连接将被彻底关闭。
四次挥手的机制保证了在连接关闭过程中,所有的数据都被正确处理,并且双方都明确知悉连接的关闭,确保了TCP连接的 可靠性 和 安全性。
TCP协议中,大写的
ACK
和小写的ack
有什么区别?
- 大写的
ACK
:
- 大写的
ACK
是 TCP 协议头部的一个标志位(Flag),全称为 Acknowledgement,用于确认接收到了对方的数据。- 当
ACK
标志位被设置为1
时,表示这个数据包包含了确认信息,即接收方已经收到了某个序列号之前的所有数据。ACK
标志位的 存在与否并不直接影响序列号,但他 决定了数据包是否包含确认信息。- 小写的
ack
:
- 小写的
ack
是一个数值,全称为Acknowledgement Number,用于指出接收方期望接收的下一个节点的序列号。- 每个TCP数据包中都有一个
ack
字段,当ACK
标志位为1时,ack
字段的值才是有效的,表示接收方成功接收并确认了ack-1
及之前节点的字节。ack
值是基于序列号的,序列号用于标识数据包中的数据字节,而ack
值则用于确认这些字节已经被正确接收。
三、Wireshark抓包验证
3.1 如何捕获三次握手、四次挥手
显示过滤器中输入如下内容:
# 筛选目的地址为 192.168.1.164 的HTTP请求
http && ip.dst == 192.168.1.164
在控制台执行如下命令:
curl http://192.168.1.164:6302/
查看 Wireshark 的捕获结果如下:
点击请求信息,可以看到当前 HTTP 请求的 Stream index
为 4,在显示过滤器中输入如下指令:
tcp.stream eq 4
Stream index
:流索引,是用来标识一个 TCP 或 UDP 数据流的唯一编号。当你在分析网络流量时,尤其是在追踪一个特定的会话时,Stream index
是非常有用的。
Stream index
基于以下四个因素来确定:源IP地址、目标IP地址、源端口、目的端口。
或者右键需要查看的请求,跟踪流
-> TCP Stream
,也可以快捷键 Ctrl + Alt + Shift + T。
这里我们只是通过跟踪流来查看 HTTP 对应的 TCP 协议交互情况,所以先关闭弹出的信息。
这里就可以清晰看到 TCP 协议中 三次握手
、四次挥手
所对应的请求:
3.2 TCP 三次握手的记录
第一次握手:
- 第一次连接是客户端主动要连接服务端的,可以看到传输控制协议里seq=0(seq是序列号),代表初次连接,ack=0(确认码,此时没有ACK标识位,所以ack不生效),初次连接为0。
- 其次,还要给标志位,就是Flags。初次连接需要给SYN=1的标志位表示请求建立连接。
第二次握手:
- 第二次握手是服务端的应答 6302 端口给 51707 的端口数据,初次连接所以 seq=0,ack=上一次客户端的序列号+1。
- 标志位是SYN=1和ACK=1,代表这是一个确认的应答连接。
第三次握手:
- 第三次握手是客户端61474给8089服务端的反馈,Seq=1,因为这是客户端的第二次交互了,Ack=上一次服务端连接的序列号+1。
- 标志位为:ACK,表示确认收到了连接回复,三次握手就建立连接完毕。
3.3 数据传输
第4个包是建立HTTP请求,开始传输数据。
第5个包由服务端应答客户端,seq=1 为服务的第二次处理;ack=上一个TCP的请求长度+1。
第6个包中,seq=1,因为一直没有有效的数据;ack=82,仍为之前TCP数据包的长度。
第7个包中,服务端给客户端响应HTTP数据,seq=TCP传输的长度+1,ack=82,之后都是往复循环发送数据。
3.4 TCP 四次挥手的记录
数据传输完毕之后,开始4次挥手操作。在 TCP 协议中,通常描述的四次挥手过程是这样的:
- 第一次挥手: 客户端发送一个带有
FIN
标志的 TCP 数据包给服务器,请求终止连接。这时,客户端进入FIN_WAIT_1
状态。 - 第二次挥手: 服务器接收到
FIN
后,会发送一个带有ACK
标志的 TCP 数据包给客户端,确认收到了FIN
。此时,服务器进入CLOSE_WAIT
状态,等待自己这边的数据发送完毕。 - 第三次挥手: 服务端在发送完自己所有的数据后,也会发送一个带有
FIN
标志的 TCP 数据包给客户端,请求终止连接。这是,服务器进入LAST_ACK
状态。 - 第四次挥手: 客户端接收到服务器的
FIN
后,会发送一个带有ACK
标志的TCP数据包给服务器,确认收到了FIN
。这时,客户端进入TIME_WAIT
状态,等待足够长的时间(通常是2MSL)以确保服务器收到确认,之后连接才会真正关闭。
然而,在看到我们用 wireshark 抓取到的四次挥手时,却发现 实际跟本无法与理论挂钩:
原因如下:
- 在实际的 HTTP 请求中,情况可能与通常的四次挥手有所不同,这是因为 HTTP 请求通常在一个 TCP 连接上进行多次往返通信。在 HTTP/1.1 中,默认情况下连接是保持打开状态的(
keep-alive
)。这意味着在一个完整的 HTTP 事务(请求-响应)之后,连接并不会立即关闭,而是可以继续用于后续的请求。 - 在 Wireshark 中,你看到的第一次挥手可能包含了
ACK
标志位,是因为在发送FIN
之前,客户端可能需要确认之前接收到的服务器数据。在某些情况下,客户端可能会在同一个数据包中同时发送FIN
和ACK
,这样可以减少网络往返次数,提高效率。 - 因此,即使你看到了
ACK
标志位被设置,这并不意味着四次挥手的模型不适用,而是可能反映了 HTTP 请求中 TCP 连接管理的优化行为。在HTTP的上下文中,FIN
和ACK
可以在同一挥手动作中合并,但这仍然符合 TCP 连接关闭的基本原则。
那么了解了为什么 FIN
和 ACK
标志位会合并之后,为了加深理解,我们再来看下出现这种情况的场景。
合并 FIN
和 ACK
标志位的场景:
- 数据传输完成且无额外数据待发送: 当一方向另一方发送完所有数据,并且不再有数据需要发送时,它可以将
FIN
标志位设置为1,同时确认对方之前发送的数据,将ACK
标志位也设置为1。 - 零窗口通告: 如果接收方通告的接收窗口大小为0,发送方将无法发送数据,此时发送方可以发送带有
FIN
和ACK
标志位的 TCP 数据包来关闭连接,避免等待不必要的空闲时间。 - 性能优化: 在一些实现中,操作系统可能选择合并
FIN
和ACK
以减少网络负载和延迟。
那么了解了合并 FIN
和 ACK
标志位的场景有哪些后,为了加深理解,我们再来看下合并后的TCP挥手过程是怎样的:
合并后的挥手过程:(三次挥手)
当 FIN
和 ACK
在同一个数据包中发送时,挥手过程可能会缩短至三次,这被称为 “三次挥手”。TCP 的 三次挥手
是指在断开连接时,双方各发送一个 FIN
标志位和一个 ACK
标志位来确认关闭连接。这里是如何发生的:
- 客户端发送
FIN+ACK
: 客户端决定关闭连接,发送一个带有FIN
和ACK
标志位的TCP数据包。FIN
表示它已经没有数据要发送了,而ACK
则是对服务器之前发送的数据的确认。 - 服务端回应
ACK
: 服务器接收到带有FIN
和ACK
的包后,会发送一个仅带有ACK
标志位的 TCP 数据包,确认接收到的客户端的FIN
,此时服务器进入CLOSE_WAIT
状态。 - 服务器发送
FIN+ACK
: 当服务器也完成了数据发送并准备关闭连接时,它会发送一个带有FIN
和ACK
标志位的TCP数据包。这里的FIN
表名服务器也没有数据要发送了,ACK
是对客户端之前可能发送的任何数据的确认。 - 客户端回应
ACK
: 客户端接收到带有FIN
和ACK
的包后,会发送一个带有ACK
标志位的TCP数据包,确认接收到服务器的FIN
,此时客户端进入TIME_WAIT
状态。
为什么客户端最后还要等待2MSL?
MSL(Maximum Segment Lifetime)
,TCP 允许不同的实现可以设置不同的 MSL 值。
- 保证客户端发送的最后一个 ACK 报文能够到达服务器,因为这个 ACK 报文可能丢失,站在服务器的角度看来,我已经发送了
FIN+ACK
保卫呢请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个 2MSL 时间段内收到这个重传的报文,接着给出回应报文,并且会重启 2MSL 计时器。- 防止类似于 “三次握手” 中提到了的
已经失效的连接请求报文段
出现在本连接中。客户端发送完最后一个确认报文后,在这个 2MSL 事件中,就可以使本连接持续的时间内所产生的所有报文段都从移动中消失。这样新的连接中不会出现就链接的请求报文。
整理完毕,完结撒花~🌻
参考地址:
1.用wireshark抓包来分析TCP三次握手和四次挥手操作,https://blog.csdn.net/dfBeautifulLive/article/details/121889271
2.TCP四次挥手中间两次会合并成一次吗?https://www.zhihu.com/question/477295175/answer/2042547399
3.TCP三次握手和四次挥手,https://www.bilibili.com/video/BV18h41187Ep/
4.详解 TCP 连接的“三次握手”与“四次挥手”,https://blog.csdn.net/spade_Kwo/article/details/119464901