一次HTTP请求,TCP做了什么?

理论加实践,深入第一线。
让我们通过使用 tcpdump+wiershark 工具,跟大家一起对 tcp 连接的建立、断开过程一窥究竟。

理论

众所周知,当客户端向服务端发送 http 请求时,客户端与服务端首先需要建立 tcp 连接,而建立的过程也就是我们常说的三次握手。当客户端关闭 http 连接时,会与服务端断开 tcp 连接,断开的过程也就是我们常说的四次挥手。那么,在这三次握手四次挥手的过程中,客户端与服务端到底发生了什么?当客户端发送完第一个 http 请求后,与服务端断开连接前,又都在干什么?让我们带着疑问,先看下这两张图:

三次握手

3-Way Handshaking.png

第一次握手:当客户端尝试与服务端建立连接时,首先发送一个带有【SYN】标记,且序号为 x 的数据包给服务端;

第二次握手:当服务端收到客户端的数据包后,会回复一个带有【ACK】标记的数据包给客户端,并且把客户端发送的序号标记 x 加1。与此同时,服务端也会在数据包中发送一个【SYN】标记,并且生成一个自己的序列号发送给客户端【Seq】=y;

(第二次握手,证明客户端的发送、接收能力和服务端的接收能力没有问题)

第三次握手:当客户端再次收到服务端的数据包后,会返回给服务端一个带有【ACK】标记的数据包,同时将服务端发送的序列号 y 加1作为 Ack 序号一并返回;

(第三次握手,证明服务端的发送能力没有问题。这也是面试中常会遇到的问题,为什么两次握手不可以,因为服务端需要知道自己的数据包是否发送成功)

四次挥手

4-Way Handshaking.png

第一次挥手:当客户端准备与服务端断开连接时,首先向服务端发送一个带有【FIN】标记的数据包,并且将【Seq】记为 x;

第二次挥手:当服务端收到客户端的数据包后,会向服务端返回带有【ACK】标记的数据包,并且将客户端发送的序号 x 加1返回;此时服务端不一定会立刻断开,有可能正在处理客户端之前发送的数据包。

第三次挥手:当服务端接收完数据后,会向客户端发送一个带有【FIN】标记的数据包,并且将自己的序号【Seq】设置为 y 一并发送;

第四次挥手:当客户端收到服务端发送的带有【FIN】标记的数据包后,会返回一个带有【ACK】标记的数据包,同时 Ack 的序号为服务端的序号加1。数据包发送后,客户端与服务端连接断开。

实践

接下来,我们通过实际操作,看一下理论知识是否正确

  1. 创建一个简单的 springboot 项目,端口号8888,提供 GET, POST 接口,并在虚拟机里启动:
    Screenshot 2023-06-24 174826.pngScreenshot 2023-06-24 174826.png

  2. 使用 tcpdump 监听8888端口,并将数据包信息写入 pcap 文件
    Screenshot 2023-06-24 174826.png

  3. 本地使用 postman 分别调用 POST, GET接口,调用结束后,关闭 postman,模拟客户端断开连接
    Screenshot 2023-06-24 174826.png

  4. 下载 pcap 文件,并导入 wireshark 进行查看
    Screenshot 2023-06-24 174826.pngScreenshot 2023-06-24 174826.png


观察抓包数据,我们可以获得如下信息:

  1. 序号1-3的数据包内容,即为 tcp 连接建立过程,也就是三次握手,其建立过程也确实如前文所述。
    Screenshot 2023-06-24 174826.png

  2. 当连接建立成功后,便开始发送 http 请求,我们可以观察到,两次 http 请求之间,不用再次建立 tcp 连接。

  3. 不管是POST请求,还是GET请求,都可以看到发送、返回的数据包。这也就是我们为什么需要 https 协议的原因,在下一篇文章中,会给大家分享 https 请求下,网络数据包都有哪些内容。
    Screenshot 2023-06-24 174826.pngScreenshot 2023-06-24 174826.png

  4. 当客户端发送数据结束后,与服务端断开连接前,会持续发送心跳,保持连接。

  5. 当客户端断开连接时,为什么只进行了三次挥手?与理论知识不符
    Screenshot 2023-06-24 174826.png

    这里涉及到 Linux 的 tcp 时延机制,当被挥手端第一次收到挥手端的【FIN】请求时,并不会立即发送【ACK】,而是会经过一段延迟时间后再发送,但是此时被挥手端也没有数据发送,就会向挥手端发送【FIN】请求,这里就可能造成被挥手端发送的【FIN】与【ACK】一起被挥手端收到,导致出现“第二、三次挥手”合并为一次的现象,也就最终呈现出三次挥手的情况。

    (这里要注意一点,30号数据包里的【ACK】标记是上一次服务端的心跳应答)


到此,我们对 tcp 连接的建立过程有了基本了解,希望对读者有所帮助,也欢迎各位大神对本文进行批评指正。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYuO3ZRP' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片