4. 数据包结构分析:OSI与TCP/IP模型回顾

说实话,干网络排障这么多年,我见过太多同事一上来就抓包,盯着十六进制看半天,最后跟我说「看不懂」。问题出在哪?说白了,就是没把数据包的结构搞清楚。

你想想看,Wireshark 摆在你面前,每一行都是一个数据包。你要是不知道这个包从哪来、到哪去、每一层干了什么,那跟看天书有什么区别?

我个人习惯,每次排查复杂问题前,都会先在脑子里过一遍 OSI 模型。不是为了考试,是为了定位——问题到底出在第几层。

4.1 OSI 七层模型 vs TCP/IP 四层模型

先看这张对比图,我把它贴在工位上好几年了。

核心观点:OSI 是理论模型,TCP/IP 是实战模型。Wireshark 抓到的包,严格遵循 TCP/IP 模型。

OSI 七层模型 vs TCP/IP 四层模型 OSI 七层模型 7. 应用层 (Application) 6. 表示层 (Presentation) 5. 会话层 (Session) 4. 传输层 (Transport) 3. 网络层 (Network) 2. 数据链路层 (Data Link) 1. 物理层 (Physical) TCP/IP 四层模型 应用层 (HTTP, DNS, DHCP, FTP...) 传输层 (TCP / UDP) 网络层 (IP) 网络接口层 (以太网、Wi-Fi、PPP...) 包含 OSI 的物理层 + 数据链路层 Wireshark 抓包时,重点关注:网络接口层(帧)→ 网络层(IP)→ 传输层(TCP/UDP)→ 应用层(协议数据)

这张图我建议你保存下来。每次抓包前看一眼,心里就有数了。

4.2 以太网帧结构——数据包的「信封」

Wireshark 里你看到的第一个字段,往往就是帧头。以太网帧,说白了就是数据包在物理线路上传输时的「信封」。

字段 长度(字节) 说明
前导码 7 同步时钟,Wireshark 不显示
帧起始定界符 1 标识帧开始,Wireshark 不显示
目的 MAC 6 接收方 MAC 地址
源 MAC 6 发送方 MAC 地址
类型/长度 2 0x0800=IPv4, 0x0806=ARP, 0x86DD=IPv6
数据 46-1500 上层协议数据(IP 包)
帧校验序列 4 CRC 校验,Wireshark 通常不显示

实战技巧:我在排查二层环路时,经常盯着「源 MAC」看。如果同一个源 MAC 在短时间内从不同端口出现,那八成是环路。Wireshark 里直接右键 MAC 地址 → Apply as Column,效率翻倍。

4.3 IP 头部——数据包的「导航系统」

IP 头部是网络层的核心。我记得有一次帮客户排查跨地域访问慢的问题,抓包一看,TTL 值只有 30 多,明显是路由跳数太多。这就是 IP 头部告诉我的。

字段 长度(位) 说明
版本 4 IPv4=4, IPv6=6
首部长度 4 单位 4 字节,最小 5(20 字节)
服务类型 8 DSCP + ECN,QoS 用
总长度 16 IP 包总大小(含头部)
标识 16 分片重组用
标志 3 DF=1 禁止分片,MF=1 还有分片
片偏移 13 分片在原包中的位置
TTL 8 最大跳数,每经过一个路由器减 1
协议 8 6=TCP, 17=UDP, 1=ICMP
首部校验和 16 仅校验头部
源 IP 地址 32 发送方 IP
目的 IP 地址 32 接收方 IP

注意:我曾经遇到过一个案例,某台服务器间歇性丢包。抓包后发现 IP 头部校验和错误,但 Wireshark 默认不校验这个字段。你需要手动开启:Edit → Preferences → IPv4 → Validate the IPv4 checksum if possible。打开后,坏包一目了然。

4.4 TCP 头部——可靠的「快递单」

TCP 头部比 UDP 复杂得多。为什么?因为它要保证可靠。我个人觉得,TCP 头部里最重要的三个字段是:序列号、确认号、标志位。

字段 长度(位) 说明
源端口 16 发送方端口
目的端口 16 接收方端口
序列号 32 字节流编号,用于排序和去重
确认号 32 期望收到的下一个序列号
数据偏移 4 头部长度,单位 4 字节
标志位 9 SYN, ACK, FIN, RST, PSH, URG 等
窗口大小 16 接收窗口,流量控制用
校验和 16 校验头部 + 数据
紧急指针 16 URG=1 时有效

排障要点:Wireshark 里看 TCP 问题,我一般先看这三样:

  • 三次握手——有没有 SYN → SYN-ACK → ACK?少一步就是连接失败。
  • 重传——TCP Retransmission 出现,说明网络丢包或延迟大。
  • 窗口大小——如果窗口一直为 0,说明接收方处理不过来,应用层有问题。

4.5 UDP 头部——轻量级的「明信片」

UDP 头部就简单多了。它不保证可靠,所以头部只有 8 个字节。你想想看,DNS 查询、DHCP、视频流,这些场景都用 UDP,因为快。

字段 长度(位) 说明
源端口 16 发送方端口(可选,可为 0)
目的端口 16 接收方端口
长度 16 UDP 头部 + 数据的总长度
校验和 16 可选,IPv4 中为 0 表示不校验

避坑指南:我曾经排查过一个 VoIP 语音断续的问题。抓包发现 UDP 校验和全是 0x0000。一开始以为是网卡 offload 导致,后来发现是中间防火墙把校验和字段改了。解决办法:在 Wireshark 里关掉 UDP 校验和验证,或者用 udp.checksum == 0 过滤出这些包,单独分析。

4.6 应用层协议头部——数据的「真面目」

到了应用层,才是我们真正关心的数据。HTTP 请求、DNS 查询、FTP 传输……Wireshark 会自动解析这些协议,你不需要手动去读十六进制。

但有一点要注意:应用层协议头部不是固定的。每个协议都有自己的格式。

举个例子,HTTP 请求头长这样:

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html

而 DNS 查询头是二进制结构:

字段 长度(位) 说明
事务 ID 16 匹配请求和响应
标志 16 QR(查询/响应)、Opcode 等
问题数 16 查询的问题数量
回答数 16 响应中的回答数量
权威数 16 权威名称服务器数量
附加数 16 附加记录数量

我的习惯:在 Wireshark 里看应用层协议,我从来不看原始字节。直接展开左下角的「Hypertext Transfer Protocol」或「Domain Name System」那个树形节点,Wireshark 已经帮你解析好了。你只需要关注关键字段,比如 HTTP 的响应状态码、DNS 的响应地址。

4.7 数据包封装过程——从应用层到物理层

最后,我们串一下整个过程。数据从应用层产生,一层层往下走,每一层都加上自己的头部。就像寄快递一样:

  1. 应用层:数据本身(比如 HTTP 请求体)
  2. 传输层:加上 TCP/UDP 头部(端口号)
  3. 网络层:加上 IP 头部(源/目的 IP)
  4. 数据链路层:加上以太网帧头(源/目的 MAC)
  5. 物理层:转换成比特流,发送到网线或无线

接收方收到后,从下往上逐层拆封。每一层只处理自己关心的头部,然后把数据交给上一层。

重要提醒:Wireshark 抓包时,如果开启了「混杂模式」,你能看到所有经过网卡的数据包。但要注意,有些网卡会做硬件 offload(比如 TSO、GSO),导致抓到的包看起来「超大」或者校验和错误。遇到这种情况,先关掉 offload 再抓包。命令:ethtool -K eth0 tx off sg off gso off tso off(Linux)。

嗯,数据包结构这块,说白了就是分层拆解。你只要记住每一层的职责和关键字段,以后看 Wireshark 的包,就不会再觉得是乱码了。