2. 网络协议回顾:TCP/IP协议栈、TCP三次握手与四次挥手、HTTP/HTTPS协议基础
做高并发抓包,说白了就是跟网络协议打交道。你连协议都不熟,抓回来的包就是一堆乱码。今天咱们把TCP/IP协议栈、三次握手、四次挥手,还有HTTP/HTTPS这些基础再过一遍。嗯,都是老生常谈的东西,但每次讲抓包课,我都要强调一遍——基础不牢,地动山摇。
2.1 TCP/IP协议栈:分层模型与核心职责
TCP/IP协议栈,我习惯把它理解成「快递分拣系统」。每一层只干自己的活,上层只管把包裹扔给下层,下层只管把包裹送到下一站。这种分层设计,让网络协议变得异常灵活。
咱们直接看这张图,一目了然:
每一层封装时都会加上自己的头部信息。抓包时你看到的那些乱七八糟的字节,其实就是一层层头部堆叠的结果。我个人习惯在排查问题时,先从应用层往下捋,看是哪一层出了问题。
核心要点:抓包时,你看到的每一个数据包,都包含了从网络接口层到应用层的完整头部信息。理解分层,才能看懂包结构。
2.2 TCP三次握手:建立连接的「双向确认」
TCP是面向连接的协议。什么叫「面向连接」?就是通信前,双方得先打个招呼,确认对方在线、愿意聊天、能收能发。这个打招呼的过程,就是三次握手。
我曾经在排查一个高并发连接超时问题时,发现服务端半连接队列满了,导致大量握手失败。那次之后,我对三次握手的理解就再也不是书本上的死知识了。
咱们用表格把三次握手的过程拆开看:
| 步骤 | 发送方 → 接收方 | 报文标志位 | 核心含义 |
|---|---|---|---|
| 第一次握手 | 客户端 → 服务端 | SYN=1, seq=x | 「嘿,我想跟你建立连接,我的初始序号是x」 |
| 第二次握手 | 服务端 → 客户端 | SYN=1, ACK=1, seq=y, ack=x+1 | 「收到!我同意,我的初始序号是y,我期待你下一个包序号是x+1」 |
| 第三次握手 | 客户端 → 服务端 | ACK=1, seq=x+1, ack=y+1 | 「好的,我知道了,咱们开始传数据吧」 |
你想想看,为什么非得三次?两次不行吗?
我简单解释一下:如果只有两次握手,服务端无法确认客户端是否收到了自己的SYN+ACK。万一这个包丢了,客户端以为自己没连上,服务端却以为连上了,就会白白浪费资源等待数据。三次握手,本质上是「双方各自确认对方的接收能力正常」。
抓包小技巧:用Wireshark过滤三次握手,直接输入 tcp.flags.syn == 1。你会看到三个包:第一个只有SYN,第二个SYN+ACK,第三个只有ACK。少一个都不行。
2.3 TCP四次挥手:优雅地「说再见」
有连接就有断开。四次挥手,就是TCP断开连接的标准流程。为什么是四次?因为TCP是全双工的,双方都要独立关闭自己的数据通道。
流程是这样的:
- 第一次挥手:主动方(通常是客户端)发送FIN包,告诉对方「我没数据要发了」。
- 第二次挥手:被动方回复ACK,说「知道了,但我可能还有数据要发」。
- 第三次挥手:被动方发完所有数据后,发送FIN包,说「我也没数据了」。
- 第四次挥手:主动方回复ACK,说「收到,再见」。然后进入TIME_WAIT状态。
这里有个坑,我踩过不止一次——TIME_WAIT。主动关闭方在发送最后一个ACK后,不会立即关闭连接,而是等待2MSL(最大报文生存时间)后才真正释放。为什么?
说白了,就是为了防止最后一个ACK丢失。如果丢了,被动方会重发FIN,主动方还能再回复一次ACK。在高并发场景下,TIME_WAIT连接过多会耗尽端口资源。我曾经在线上看到一台服务器上有几万个TIME_WAIT连接,新连接死活建不起来。
避坑指南:高并发服务端,如果短连接特别多,一定要关注 netstat -n | grep TIME_WAIT 的数量。我曾经因为没注意这个,导致线上服务大面积超时。解决方案包括开启 tcp_tw_reuse 和 tcp_tw_recycle(但注意,tcp_tw_recycle在NAT环境下有坑,慎用)。
2.4 HTTP/HTTPS协议基础:应用层的「对话规则」
HTTP是应用层最常用的协议。说白了,它就是客户端和服务端之间约定好的「对话格式」。你请求什么资源,用什么方法,带什么头部,服务端返回什么状态码,都在HTTP协议里定义好了。
咱们看一个最简单的HTTP请求和响应:
// HTTP请求
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
// HTTP响应
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<html>...</html>
HTTP本身是明文传输的。你抓包时,直接就能看到请求和响应的全部内容。这在早期互联网还行,但现在谁还敢用明文?所以就有了HTTPS。
HTTPS = HTTP + TLS/SSL。TLS在传输层之上、应用层之下,加了一层加密和认证。抓包时,你看到的HTTP内容全是密文,除非你配置了SSL解密(比如用Wireshark导入私钥或使用SSLKEYLOGFILE环境变量)。
我记得有一次帮客户排查一个HTTPS连接慢的问题。抓包一看,TLS握手阶段来回折腾了七八个包,比正常多了两倍。最后发现是客户端和服务端支持的密码套件不匹配,一直在协商降级。嗯,从那以后,我排查HTTPS性能问题时,第一件事就是看TLS握手花了几个RTT。
关键对比:
| 特性 | HTTP | HTTPS |
|---|---|---|
| 默认端口 | 80 | 443 |
| 加密 | 无(明文) | TLS/SSL加密 |
| 抓包可见性 | 直接看到全部内容 | 需要解密才能看到 |
| 性能开销 | 低 | 高(TLS握手+加解密) |
| 安全性 | 低(易被窃听/篡改) | 高(防窃听/防篡改/身份认证) |
最后说一句,HTTP协议版本也在演进。HTTP/1.1有队头阻塞问题,HTTP/2通过多路复用解决了,但TCP层面仍有队头阻塞。HTTP/3直接换成了QUIC(基于UDP)。这些在高并发抓包时都会遇到,咱们后面的章节会详细展开。
嗯,协议基础就回顾到这儿。这些内容虽然基础,但每次抓包排查,最终都会回到这些最根本的原理上。你把这些搞透了,抓包时看到那些标志位、状态码、握手过程,心里就有底了。