ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Wireshark数据包长度统计实战:从字段解析到发送方向分析

Wireshark数据包长度统计实战:从字段解析到发送方向分析 有次线上排查应用响应慢抓完包一百多万个我盯着报文列表翻了五分钟头皮发麻。后来改了个习惯抓到 pcap 之后先看长度。Wireshark 抓包里“数据包长度”是一组最不起眼的数字却是最快能把流量分类的钥匙。统计发送方向的数据包长度能判断链路是在跑满载大包还是碎片小包能定位是不是 MTU 配置出了岔子甚至能看出应用层是不是没开 TCP_NODELAY。这篇文章就围绕 Wireshark 抓包中“统计发送的数据包长度”这件事把字段含义、统计窗口、过滤语法、命令行用法和踩坑经验全部过一遍适合刚开始学抓包的同学也适合抓包很多年但没仔细研究过长度字段的老手。1. 三个“长度”字段先分清Frame Length、IP Length 和 TCP Length很多人一打开 Wireshark 就说“看包长度”但 Wireshark 里跟长度沾边的字段有好几个。统计之前不把这些字段分清后边全白做。最常见的三个长度概念是 Frame Length、IP Total Length 和 TCP Length它们的覆盖范围完全不同。1.1 Frame 里的 “bytes on wire” 和 “bytes captured”选中任意一个数据包展开最上层的 Frame 协议你会看到这样两行Frame 1514 bytes on wire (12112 bits), 1514 bytes captured“bytes on wire” 表示这个以太网帧在线路上占用的总字节数也就是我们通常说的 frame.len。“bytes captured” 表示抓包工具实际捕获了多少字节。正常情况下两者相等但如果你在抓包时设置了 snaplen抓包长度上限或者网卡驱动只返回了部分数据captured 会小于 on wire。统计长度时我一般以 bytes on wire 也就是 frame.len 为准因为它代表的是链路上真实传输的报文大小。frame.len 包含完整的以太网头部通常是 14 字节目的 MAC 6 字节、源 MAC 6 字节、EtherType 2 字节。如果报文带了 802.1Q VLAN Tag还要额外加 4 字节。1.2 IP 总长度、TCP 载荷长度一张表说清关系Frame 之下IP 层有 ip.lenTCP 层有 tcp.lenUDP 层有 udp.length。它们之间是“包含关系”但很多新手会把它们混为一谈尤其是 tcp.len 和 ip.len。ip.lenIPv4 报文总长度包含 IP 头部和 IP 载荷。在 IPv4 头里就是 Total Length 字段。tcp.lenWireshark 计算出的 TCP 段载荷长度等于这个 TCP 段里“应用数据”的字节数不包括 TCP 头也不包括 IP 头。udp.lengthUDP 头加 UDP 载荷的长度最小 8 字节。拿一个最常见的满载荷 TCP 数据段来举例以太网帧 1514 字节包含 14 字节以太网头、20 字节 IP 头、20 字节 TCP 头、1460 字节应用数据。各字段值如下字段代表范围满载荷TCP段典型值frame.len以太网帧整体长度1514ip.lenIP头 IP载荷1500tcp.len仅TCP载荷1460udp.lengthUDP头 UDP载荷按业务而定一个纯 ACK 包则是另一个极端frame.len 大约 54 字节到 66 字节ip.len 40 字节左右IP 头 20 TCP 头 20而 tcp.len 0因为它没有任何应用数据。1.3 手动计算 TCP 实际载荷的公式如果你看到某个包的 tcp.len 显示为空或者想自己心算验证可以用这个公式tcp.len frame.len - 14(以太网头) - 4(如果有VLAN Tag) - ip.hdr_len - tcp.hdr_len注意ip.hdr_len 不一定是 20TCP 头也不一定是 20。IP 带了 Options 时头会变长TCP 带了时间戳、SACK 等选项时头同样会变长。所以我在实际分析中从不算这个公式直接在显示过滤器里用 tcp.len 字段Wireshark 早就帮你算好了。手动算公式的意义只有一个当你看到长度不是一个“整数感”的值时心里有数可能是 Options 占的字节。2. 不用逐包翻用 Packet Lengths 直方图看整份抓包的长度分布如果 pcap 文件有几百 MB你不可能逐个包去看长度。Wireshark 的 Statistics - Packet Lengths 就是专门给你看“全貌”的。这个功能平时用的人不多但排查问题时效率极高。2.1 Packet Lengths 窗口怎么打开和显示过滤器如何联动菜单栏路径是 Statistics - Packet Lengths。打开后Wireshark 会把当前主界面的显示过滤器结果按照长度区间分组。默认分组的长度范围大致是 40-79、80-159、160-319、320-639、640-1279、1280-2559 这样的倍数区间。每一行会显示该区间内的包数量、百分比、累计数量和累计百分比。这里有个最关键的技巧这个统计窗口会同步主界面的显示过滤器。也就是说你可以在主界面先构造好“只看发送方向”的过滤条件比如ip.src 192.168.1.10再打开 Packet Lengths它只会统计过滤后的包。过滤条件不同统计结果完全不同千万别拿着不过滤的全局统计去看某个主机的发送行为。2.2 读分布形态一眼看出流量属于哪种类型长度分布的形状本身就是诊断结论如果大量包集中在 40-79 字节区间说明这份抓包里主要是 TCP 控制包比如 SYN、纯 ACK、Keep-Alive。连接频繁建立、或者接收方在不停确认数据都会形成这种形态。如果在 1280-2559 区间有非常集中的柱子说明有大量接近 MTU 满载的数据段最常见的就是文件传输、视频流这类大块数据。如果分布很散中间一堆几百字节的包那就要小心了。这种情况通常意味着应用层在发送小段数据或者 TCP 分段本身没有顶满 MSS。我在实际使用中总结了一个经验把鼠标放到统计表的长度区间上双击某一行可以直接在主界面过滤出对应长度的包然后结合其他列去确认这些包到底是什么协议、什么行为。这是快速从“统计全貌”切换到“具体报文”的最好方式。2.3 调整粒度与导出结果Packet Lengths 窗口下方有一个范围调整滑块可以改变分组的粒度。默认的分组比较粗比如 640-1279 一个区间如果你发现这一段特别多可以把粒度调细看看具体是 640-799、800-959 还是 960-1279进一步锁定规律。窗口支持把统计结果复制出去方便贴到文档里做分析报告。另外顺便提一句如果你想知道“每个协议占了多少字节”可以用 Statistics - Protocol Hierarchy。它不是按长度区间而是按协议栈来统计报文数和字节数。把 Packet Lengths 和 Protocol Hierarchy 结合起来看能很清楚地知道这份流量到底是 DNS 这种小包为主还是 TCP 大数据块为主。3. 精确捞包按长度范围过滤出你关心的发送报文统计窗口解决的是“整体分布长什么样”但更多时候我们要把特定长度的包筛出来细看。Wireshark 的显示过滤器对长度字段支持得很好下面这些过滤表达式是我平时用得最频繁的。3.1 按 frame.len / ip.len / tcp.len 过滤的常见场景过滤表达式用途frame.len 1514找出超过标准以太网最大帧的包排查巨型帧或网卡 offload 异常frame.len 64找出小于最小以太网帧的包排查异常短帧tcp.len 0筛出所有不含有效载荷的 TCP 包比如纯 ACK、SYN、FINtcp.len 0 tcp.len 100找出发送方向数据量极小的 TCP 段常用于排查“小包碎包”问题ip.len 1500排查 IP 层大于 MTU 的报文通常意味着分片或巨型帧udp.length 1400找出接近满载的 UDP 报文比如大流量 DNS over UDP 场景举个例子排查 MTU 问题的时候我习惯用frame.len 1472 icmp去筛选 Ping 大包。1472 是标准 MTU 1500 减掉 20 字节 IP 头和 8 字节 ICMP 头之后的值。如果对方设备 MTU 不够你会看到有去无回、或者看到 ICMP 分片错误消息长度分布也能明显看到断档。3.2 把长度字段变成列滚动列表就能发现异常Wireshark 默认的报文列表里没有长度列你可以手动加。在报文列表上方的列名处点右键选择 Column Preferences新增两列字段名分别填 frame.len 和 tcp.len。更快的办法是展开某个包的 Frame 或 TCP 协议字段右键对应的长度字段选择 Apply as Column。加了这两列之后整个列表滚动起来非常有信息量。你会看到一串 1514 的满载荷段中间偶尔插进来几个几十字节的纯 ACK这是正常现象但如果你看到大量几百字节的段夹杂在满载荷段之间就要想想为什么应用数据没有把 MSS 填满。3.3 组合条件的排障场景长度字段最常见的用法不是单独用而是和 IP、协议、时间戳组合。比如只看本机向上行方向发送的数据段ip.src 192.168.1.10 tcp.len 0想看发送方向小于 100 字节的数据段并排除重传ip.src 192.168.1.10 tcp.len 0 tcp.len 100 !tcp.analysis.retransmission想找发送间隔超过 200ms 的大包tcp.len 1000 frame.time_delta 0.2第二种场景非常有代表性。如果这类小数据包数量特别多几乎可以断定应用层在频繁 write 小块数据到 socket。这时候单纯调大 TCP 缓冲区没用根因在应用侧要么合并写入要么开启 TCP_NODELAY 避免 Nagle 算法把数据憋住。4. 一次完整实操统计 HTTP 会话中“本机发送方向”的数据包长度前面都是方法论这一节走一遍完整流程。目标很具体用 Wireshark 统计一个 HTTP 访问过程中本机发送方向的数据包长度分布并从中判断是否存在异常。4.1 抓包与识别方向的基本方法假设本机 IP 是 10.0.0.2访问的目标服务器是 93.184.216.34。抓完包后先在过滤器中输入ip.addr 93.184.216.34眼前就只剩和目标服务器的交互流量。要看“发送方向”的严格定义就是ip.src 10.0.0.2。如果你觉得 IP 记不清还有一个更稳妥的方法Statistics - Conversations在 TCP 页签里找到这对 IP 对应的一行能看到两个方向各自的 Packets 和 Bytes 统计。在 Conversations 窗口双击某一会话主界面会自动应用过滤只显示该会话的包。随后你想统计哪个方向再加一条ip.src 10.0.0.2即可。4.2 一个 HTTP 请求中各关键包的典型长度为了让你对“长度”有直接体感这里列出一次非常干净的 HTTP 请求中常见包的典型长度范围。不同操作系统、不同 TCP Options 组合会导致长度略有差异但量级不会变。包类型frame.len 典型值tcp.len是否出现在本机发送方向SYN 第一次握手约 54-70 字节0是本机主动发起SYNACK 第二次握手约 54-70 字节0否ACK 第三次握手约 54-70 字节0是HTTP GET 请求视 Headers 而定常见 300-600 字节请求体长度是服务器回应的满载荷段15141460否服务器回应的最后一小段不定比如 354剩余不足 1460否本机确认收到的纯 ACK约 54-70 字节0是从这个表能看到一个很容易被忽略的事实即使我们是“发送方向”统计出来的大量短包其实是 ACK不是应用主动发出去的数据。如果你只关心应用有效数据应该严格使用ip.src 10.0.0.2 tcp.len 0来过滤。4.3 用 Packet Lengths 统计发送方向并下结论实际操作如下主界面过滤器输入ip.src 10.0.0.2。打开 Statistics - Packet Lengths。看 40-79 区间占多大比例再看 1280-2559 区间占多大比例。如果 40-79 区间占了八成说明这个方向的报文绝大多数是控制包。对于一个下载场景来说这是正常的因为接收方不会发大量数据只需要回 ACK。但对于一个上传场景来说就要警惕如果你本机在传输大文件发送方向应该是大量 1514 的满载段而 40-79 区间占比不应该太高。4.4 结合流量图验证长度规律长度统计得出的结论可以再用 Statistics - TCP Stream Graphs - Time Sequence (Stevens) 来验证。这个图会把 TCP 段的长度画成阶梯状。如果图里大部分阶梯是很矮的横线说明发送的数据段都很短如果出现大量近乎垂直的长竖线说明一段一段的数据都是满负荷 1460 字节。长度分布和图形相互印证之后结论就比较可信了。5. 没有图形界面的服务器场景用 tshark 命令快速统计长度分布很多时候 pcap 文件在 Linux 服务器上不想来回传或者要批量分析几十个文件。这时候 Wireshark 的图形界面用不上直接用 tshark 命令配合标准文本处理工具效率非常高。5.1 导出长度字段序列tshark 的-T fields -e frame.len可以把指定字段逐行打印出来。结合显示过滤器可以先限定方向# 只看本机发送方向的所有包包长 tshark -r capture.pcap -Y ip.src10.0.0.2 -T fields -e frame.len | head # 只看本机发送方向、且包含有效载荷的TCP包 tshark -r capture.pcap -Y ip.src10.0.0.2 tcp.len0 -T fields -e frame.len | head这两条命令的价值在于后续任意文本处理都能接上。 awk、sort、uniq、python 都行。5.2 统计最大值、最小值、平均值排查“数据包长度异常”最常用的是一条 awk 命令tshark -r capture.pcap -Y ip.src10.0.0.2 -T fields -e frame.len | \ awk {sum$1; n; if ($1max) max$1; if (n1 || $1min) min$1} \ END {printf count%d avg%.1f min%d max%d\n, n, sum/n, min, max}实际输出类似count18624 avg682.3 min54 max1514avg 682 意味着平均包长处于中等水平感觉上不像纯控制包流。如果你看到 avg 只有 70 左右而应用明明在传数据那就说明数据被拆成了大量小包。5.3 按长度档位统计频次想知道哪些长度值出现最多用 sort 和 uniq -c 组合tshark -r capture.pcap -Y tcp.len0 -T fields -e frame.len | \ sort -n | uniq -c | sort -rn | head -20输出里第一列是包数量第二列是帧长度。如果排在前面的全是 1514 和 54 附近的值属于“满载数据 纯控制包”的正常组合。如果排在前面的长度非常分散比如 283、467、551 这类说明应用层写入的数据大小没有和 TCP 缓冲区对齐每条连接都在发送自定义大小的块这本身不一定有问题但结合高延迟、低吞吐一起看时通常能定位到应用侧。5.4 capinfos 看全局平均长度如果只是想知道整份抓包的平均包长、报文总数不需要 tshark 过滤直接使用 capinfoscapinfos capture.pcap输出里可以关注这几项Number of packets报文总数Data packet size average平均数据包大小Data byte rate每秒字节数Average packet rate每秒报文数capinfos 是 Wireshark 套件自带的工具和 tshark 在同一个目录正常情况下装了 Wireshark 就有。5.5 一条命令完成发送方向长度分布分析最后分享一个我实际在服务器上排查时常用的完整命令链echo 发送方向总览 tshark -r capture.pcap -Y ip.src10.0.0.2 -T fields -e frame.len | \ awk {sum$1; n; if ($1max) max$1; if (n1 || $1min) min$1} \ END {printf count%d avg%.1f min%d max%d\n, n, sum/n, min, max} echo 长度TOP20 tshark -r capture.pcap -Y ip.src10.0.0.2 tcp.len0 -T fields -e frame.len | \ sort -n | uniq -c | sort -rn | head -20一条命令包住了数量、平均值、最大值和最常出现的长度档位用来快速判断链路状态非常够用。6. 长度统计最容易踩的五个坑以及一次真实排障记录前面的方法都很顺手但实际用的时候有几个坑我踩过不止一次每次都能多耗几个小时。这里单独列出来。6.1 所有大包长度卡在同一个数字snaplen 截断如果抓包时设置了抓包长度限制超过限制的包会被截断。最常见的结果是大量包的 frame.cap_len 都等于同一个值比如 96、128、512。更迷惑的是截断后 frame.cap_len 和 frame.len 在 Wireshark 里的显示是一样的因为 Wireshark 只拿到了截断后的数据无法知道原始长度。所以当你看到大批包的长度恰好是 96、128、512 这类整数且包内应用层数据明显不完整第一反应应该是“抓包长度被限制了”。解决方法是重新抓包时不加长度限制tcpdump 用-s 0Wireshark 的抓包选项里把“Limit each packet to”调成 default 或最大。顺带一提过滤器frame.cap_len frame.len可以找出已经被明确标记截断的包但截断模式下两者相等的情况更多靠这个过滤并不保险。6.2 网卡 offload 打开后出现超大帧和坏校验TSO、GRO、GSO 这类网卡加速会把多个报文合并成一个大块再交给抓包接口Wireshark 里会出现几万字节的以太网帧并伴随 TCP checksum 显示为 bad。这种长度统计完全失真不能拿来做分析。Linux 下排查时需要确认网卡 offload 状态必要的时候关闭ethtool -k eth0 | grep -E tcp-segmentation-offload|generic-receive-offload关闭命令ethtool -K eth0 gro off gso off tso offWindows 下的 Wireshark 则可以去网卡驱动属性里关闭 Large Send Offload 和 Large Receive Offload。抓性能数据时建议提前关掉否则长度分布和校验和都不真实。6.3 别忘了 802.1Q VLAN Tag 的 4 字节在 Trunk 口上抓包时每个帧都会多出 4 字节的 VLAN Tag正常最大帧因此从 1514 变成 1518。如果你直接用frame.len 1514去筛选巨型帧会把带 VLAN 的普通满载帧也捞出来。判断时要根据抓包环境做调整有 VLAN 就按 1518 算没 VLAN 按 1514 算。更精确的做法是先过滤 VLAN 再看长度frame.len 1518 vlan frame.len 1518这 4 字节在统计大文件传输时影响不大但在你追查 MTU 争议时非常关键。6.4 最小帧填充54 还是 64 的问题以太网规定最小帧长是 64 字节含 FCS而 Wireshark 默认抓到的以太网帧通常不含 FCS所以很多纯 ACK 包显示为 54 字节或者 60 字节。有些刚接触抓包的人以为看到了损坏包其实只是因为抓包环境没有把填充字节和 FCS 记录进来。只要你用tcp.len 0能筛出这些短包并且它们都是 ACK、SYN、FIN 这类控制报文就完全不用担心。不要因为在 Packet Lengths 里看到大量 40-79 字节的包就以为是网络故障。6.5 广播、ARP 干扰了“发送方向”的统计如果你只过滤了ip.src 本机IPARP 和 DHCP 这类广播报文也会被算进长度统计里。ARP 请求包很小往往只有几十字节会把整体平均长度拉低。严谨的统计建议至少加上 tcp或者 ip把非 IP 报文排除掉。尤其是排查“为什么发送方向平均包长这么低”的时候先排除 ARP 再下结论。6.6 真实案例发送方向全是小包问题出在应用层写小块数据去年排查一个内部系统大文件上传速度上不去的故障。抓包后我直接用 Packet Lengths 看发送方向的长度分布结果 40-79 区间的包占比超过 70%满载 1514 的包寥寥无几。一开始我怀疑是 MTU 或 MSS 协商问题但查看 SYN 里的 MSS 选项协商值是正常的 1460。继续深入后在时间戳上发现规律本机每隔几十毫秒就发送一个一两百字节的 TCP 段而不是积攒到 1460 字节一次性发出去。这是典型的应用层小数据写入场景再加上 Nagle 算法没关TCP 会等待 ACK 到达后再把缓冲区里的小块数据发出去造成延迟叠加。后来在应用侧开启 TCP_NODELAY并把多次小写入合并成一次大写入后发送方向的长度分布立刻变成了满载段为主传输速度翻了将近三倍。那次之后我抓包第一件事永远是看长度分布。它不复杂却是建立流量体感最直接的方式先看分布再按方向过滤最后定位到具体连接的规律。相比一上来就翻协议解析这个路径要快得多。
返回列表