「业务应用程序的服务器通信一个月失败几次。应用程序日志只写『超时』。当时服务器端日志没有对应错误。不知道怎么重现」——故障调查咨询里,这种形状不断出现。
应用程序日志只留下应用程序「决定要写」的东西。你看得见结果是超时,但连接要求(SYN)有没有回复、连上之后服务器是否沉默、是不是被 RST 切断、数据包有没有到达目的地,都活在日志下一层——实际走过线路的数据包。若 Process Monitor 是往下一层看文件与注册表访问的方法,数据包捕获就是往下一层看通信的方法。
flowchart TB
accTitle: 应用程序日志下一层的数据包
accDescr: 应用程序日志只留下应用程序决定要写的内容;SYN 有没有回复、连接后是否沉默、是否被 RST 切断、数据包有没有到达,只存在实际走过线路的数据包里
log["应用程序日志"] --> dec["只留下决定要写的内容"]
dec --> to["结果只剩一句超时"]
to -->|往下一层看| pkt["实际走过线路的数据包"]
pkt --> q1["SYN 没有回复?"]
pkt --> q2["连接后沉默?"]
pkt --> q3["被 RST 切断?"]
pkt --> q4["有到达目的地吗?"]
图 1: 日志只留下结果;超时的内情只存在下一层的数据包里。
人们卡住的典型点是「客户服务器不能安装 Wireshark」这个限制。变更管制或资安政策不批准为调查加装软件的现场并不少见。不过 Windows 已经内置两套数据包捕获工具:pktmon 与 netsh trace。用操作系统内置工具捕获,把文件带回自己的电脑用 Wireshark 读——这样分工,即使现场禁止安装也能看到数据包。
本文给中小企业 IT 人员与 Windows 应用程序开发者,整理 pktmon、netsh trace、Wireshark 的选择方式与各自的实务步骤。回环流量的陷阱、该在用户端还是服务器捕获、如何与 TLS 隐藏载荷共处、以及捕获与应用程序日志的对照,都以 2026 年 8 月当时的一手资料说明。
1. 先讲结论
- 「用内置工具捕获、用 Wireshark 读」是现场的基本分工。 即使客户服务器不能装软件,pktmon 与 netsh trace 已内置于 Windows。把捕获日志转成 pcapng,在自己机器的 Wireshark 分析。12
- pktmon 是 Windows 10 / Windows Server 2019 以后内置的数据包捕获工具。 用法是注册过滤器、开始、停止、转换四步,独特之处是能看到网络堆栈哪个组件丢了数据包(丢弃原因)。34
- netsh trace 是较旧的内置工具,能把一组 ETW 提供者当成「情境」一次启用。 除了数据包,也留下 Windows 组件内部事件,加上 persistent=yes 捕获就能撑过重启。56
- 两套工具都写 ETL,Wireshark 不能直接开启。 pktmon 用
pktmon etl2pcap转 pcapng,netsh trace 用 Microsoft 开源的 etl2pcapng。12 - Microsoft 自己指向「先 pktmon,不够再用 netsh trace,协议分析用 Wireshark」。 本文分工遵循这项官方建议。7
- 预设 pktmon 只记录每个数据包的前 128 字节。 若打算在 Wireshark 读载荷,开始时别忘了
--pkt-size 0(记录整个数据包)。8 - 打到 localhost 的流量不会出现在一般捕获。 它不经过 NIC。Wireshark 用 Npcap 的回环网卡,内置工具用 pktmon 的堆栈内捕获。9
- 即使 TLS 藏起载荷,仍能知道很多事。 连接建立、TLS 握手成败、RST、哪一边沉默,加密状态下仍可见。经 SSLKEYLOGFILE 解密是仅限开发环境的手法。10
- 捕获文件就是通信本身。 预设它可能含认证信息与个人资料,把最小必要捕获与交出前缩小范围写进程序。
2. 三套捕获工具与怎么选
先用一张表看三套工具的角色。
| pktmon | netsh trace | Wireshark | |
|---|---|---|---|
| 取得方式 | Windows 10 / Windows Server 2019 以后内置3 | Windows 早已内置(pktmon 之前的系统也能用) | 需另外安装 |
| 主要角色 | 数据包捕获、丢弃侦测、计数器 | 数据包捕获 + Windows 组件的 ETW 事件 | 分析捕获资料(真正目的地) |
| 输出格式 | ETL(用 etl2pcap 转 pcapng)1 | ETL+.cab(用 etl2pcapng 转 pcapng)62 | pcapng |
| 独特之处 | 堆栈内丢弃位置与原因4 | 依情境绑定提供者、跨重启捕获5 | 显示过滤器、TCP 分析、统计、GUI |
| 权限 | 系统管理员 | 系统管理员 | 捕获需相当于系统管理员(只分析则不必) |
一句话,pktmon 与 netsh trace 是「捕获」工具,Wireshark 是「读」的工具。Wireshark 也能捕获,但不能装的地方就用不了。反过来说,也能把内置工具的 ETL 转成文字来读,但没有显示过滤器与 TCP 分析地盯著看很痛苦。「现场用内置工具捕获,转成 pcapng,在自己机器的 Wireshark 读」是受限现场的最短路径。
flowchart TB
accTitle: 用内置工具捕获、用 Wireshark 读
accDescr: 现场用 pktmon 或 netsh trace 捕获 ETL,各自用转换工具转成 pcapng,再在自己机器的 Wireshark 分析
pk["pktmon(内置)"] --> etla["ETL 档"]
ns["netsh trace(内置)"] --> etlb["ETL+.cab"]
etla -->|pktmon etl2pcap| pcap["pcapng"]
etlb -->|etl2pcapng| pcap
pcap --> ws["在自己机器的 Wireshark 分析"]
图 2: 现场用内置工具捕获 ETL,转成 pcapng,在自己机器的 Wireshark 读。
Microsoft 的数据包遗失调查指南也是这个形状:先用 pktmon 捕获并隔离原因,不够再进到 netsh trace start scenario=InternetClient 这类组件层追踪,协议行为用 Wireshark 分析。7
要读懂数据包实际显示什么,先有 Ethernet、IP、TCP、应用程序资料层层堆栈的图像也有帮助。层次解剖见「把OSI参考模型彻底看懂」。
3. pktmon 实务 — 筛选、开始、停止、转换
pktmon 的基本流程是四步。在提升权限的终端执行。
:: 1. 先注册过滤器以缩小目标(服务器 192.168.10.20 的 TCP 8443)
pktmon filter add App8443 -i 192.168.10.20 -t tcp -p 8443
pktmon filter list
:: 2. 开始捕获。记录完整数据包,在 1GB 环形缓冲区中覆盖
pktmon start --capture --pkt-size 0 --file-name C:\temp\app-timeout.etl --file-size 1024 --log-mode circular
:: 3. 复现故障。等待期间可用 counters 查看流量与丢弃
pktmon counters --drop-reason
:: 4. 停止,再转为 Wireshark 用的 pcapng
pktmon stop
pktmon etl2pcap C:\temp\app-timeout.etl --out C:\temp\app-timeout.pcapng
:: 5. 清理已注册的过滤器(过滤器会一直保留到你显式删除)。
:: 注意:filter remove 不能指定名称;它会删除「全部」已注册过滤器。
:: 若机器上可能还留着另一次调查的过滤器,先用 pktmon filter list 确认
pktmon filter remove
flowchart TB
accTitle: pktmon 基本步骤
accDescr: 用过滤器缩小目标、开始捕获、重现故障、停止、用 etl2pcap 转成 pcapng,最后移除已注册的过滤器
fa["1. 用 filter add 缩小目标"] --> st["2. 用 start --capture 开始捕获"]
st --> re["3. 重现故障"]
re -.-> ct["用 counters 看流量与丢弃"]
re --> sp["4. 停止"]
sp --> cv["用 etl2pcap 转成 pcapng"]
cv --> rm["5. 用 filter remove 清理"]
图 3: pktmon 从注册过滤器开始,接著捕获、停止、转换,最后明确移除过滤器。
要记住的重点:
- 开始捕获前先注册过滤器。 Microsoft 文件也强烈建议开始前套用过滤器,因为捕获全部流量太吵。过滤器可指定 IP 地址、连接埠、MAC 地址、协议、VLAN ID 等,最多注册 32 个。多个过滤器是 OR:数据包符合其中任一就会被记录。3
- pktmon 过滤器不区分来源与目的地。
-i 192.168.10.20代表「这个地址是来源或目的地的数据包」。方向稍后用转换后的 Wireshark 显示过滤器缩小。3 - 预设数据包大小是 128 字节。 分析标头够用,但若还要应用程序资料,用
--pkt-size 0记录整个数据包。8 - 日志预设是 circular(环形缓冲)模式,预设大小 512MB。 可用
--file-size改上限,--log-mode real-time即时印到画面且不建立日志档。先用即时模式确认真的看得到关心的流量,再设正式捕获,就能避开空拍。8
flowchart TB
accTitle: pktmon 过滤器如何生效
accDescr: 多个已注册过滤器以 OR 比对记录,指定地址不区分来源与目的地,方向稍后用转换后的 Wireshark 显示过滤器缩小
f1["过滤器 1"] --> orc["符合任一就记录"]
f2["过滤器 2"] --> orc
f3["过滤器 3(最多 32)"] --> orc
orc --> rec["写入捕获日志(OR)"]
rec -.-> nodir["不区分来源与目的地"]
nodir -.-> ws["转换后在 Wireshark 缩小方向"]
图 4: 多个过滤器以 OR 运作,主机是来源还是目的地在转换后用 Wireshark 缩小。
3.1. 只有 pktmon 做得到的事 — 看到数据包在哪里被丢弃
pktmon 相对 Wireshark 的独特价值是 它不是在单一 NIC 捕获,而是在网络堆栈内多个点捕获数据包,并能报告在哪里、为什么被丢弃(dropped)。因为看得到数据包到达哪个组件、在哪里消失,「MTU 不符」或「VLAN 筛选」这类丢弃原因不必盲搜就能接到原因。4
flowchart TB
accTitle: pktmon 在堆栈内多个点捕获
accDescr: pktmon 不是在单一 NIC 而是在网络堆栈内多个点捕获数据包,因此能连同原因报告数据包到达哪个组件、在哪里被丢弃
pin["数据包"] --> p1["在点 1 捕获"]
p1 --> p2["在点 2 捕获"]
p2 --> p3["在点 3 被丢弃"]
p3 -.-> rz["报告丢弃位置与原因"]
rz -.-> ex["例如 MTU 不符或 VLAN 筛选"]
图 5: 在堆栈内多个点捕获,就能知道数据包走到哪、在哪里被丢,并附上原因。
pktmon list显示可监视的网络组件(NIC、协议堆栈、筛选驱动程序等)及其 ID。pktmon counters --drop-reason列出各组件通过/丢弃计数与最近一次丢弃原因。分析日志前当第一刀很方便。11- 用
pktmon etl2txt转成文字时,被丢弃的数据包会带著drop与 dropReason 输出。3
「操作系统里有东西在到达应用程序前就把这包丢掉」这种怀疑,只盯 Wireshark 无法了结。这个能力例如在隔离防火墙因缺少输入规则而丢包的案例时有帮助(「Windows 防火墙与业务应用程序」)。
有一点要注意。pktmon 在堆栈多个点记录同一个数据包,原样转成 pcapng 可能让同一数据包出现不止一次。pcapng 不携带「哪个组件捕获了这包」,所以在 Wireshark 读时,标准作法是用 --component-id 选一个点转换,或用 --drop-only 把丢弃单独放到另一个档。1
flowchart TB
accTitle: 为什么转成 pcapng 后同一数据包可能出现两次
accDescr: pktmon 在堆栈多个点记录同一数据包,pcapng 不保留哪个组件捕获,因此可能出现重复;标准作法是用 component-id 缩小捕获点,或用 drop-only 档只放丢弃后再转换
same["同一数据包在多个点被记录"] --> conv["原样转成 pcapng"]
conv --> lost["捕获点信息没有带过去"]
lost --> dup["同一数据包出现不止一次"]
dup --> c1["用 --component-id 缩小点"]
dup --> c2["用 --drop-only 另存档"]
图 6: 捕获点信息不会带进 pcapng,所以标准作法是转换前先缩小捕获点。
4. netsh trace 实务 — 情境、ETL、撑过重启的捕获
netsh trace 是比 pktmon 更早进入 Windows 的追踪机制。特色是 能以「情境」一次启用与该问题相关的整组 ETW 提供者。6
:: List available scenarios and inspect the providers in a scenario
netsh trace show scenarios
netsh trace show scenario netconnection
:: Start the capture. Packet capture included, 1GB circular buffer
netsh trace start scenario=netconnection capture=yes tracefile=C:\temp\nettrace.etl maxSize=1024 filemode=circular
:: Reproduce the incident, then stop (the merge takes a little time)
netsh trace stop
- 加上
capture=yes启用数据包捕获,并用ipv4.address=192.168.10.20这类捕获过滤器缩小目标。过滤器清单在netsh trace show capturefilterHelp。6 - 停止时除了 ETL 还会产生 .cab。.cab 含网卡设定与操作系统组建等系统信息,可兼作环境搜集。6
- 同一时间只能跑一个追踪会话。开始另一次捕获前,用
netsh trace show status确认没有残留会话。6 - 加上
persistent=yes,会话就能撑过重启。 「重启后一瞬间通信失败」或「启动时服务连接失败」——这种来不及用手启动的故障,是 netsh trace 独有的地盘。5
flowchart TB
accTitle: 捕获 netsh trace 情境
accDescr: 以情境启动会启用一组 ETW 提供者,capture=yes 也会捕获数据包,停止后产生 ETL 档与 .cab 档
sc["以情境启动"] --> pv["启用提供者集合"]
sc -->|capture=yes| pc["数据包也会被捕获"]
pv --> re["重现故障"]
pc --> re
re --> sp["停止"]
sp --> etl["ETL 档"]
sp --> cab[".cab(系统信息)"]
图 7: 以情境启动会启用一组提供者,停止后产生 ETL 与 .cab。
4.1. 让 ETL 能在 Wireshark 读 — etl2pcapng
netsh trace 的 ETL 不能直接在 Wireshark 开启。Microsoft 在 GitHub 公开的开源工具 etl2pcapng,会把以 netsh trace start capture=yes 捕获的 ETL 里的数据包转成 pcapng。2
etl2pcapng.exe C:\temp\nettrace.etl C:\temp\nettrace.pcapng
转换时 etl2pcapng 会把每个数据包相关的进程 ID 写成数据包注解。能在 Wireshark 看到「这是哪个进程的流量」,同一台服务器上多个应用程序在通信时很有帮助。2
ETW 事件那一侧(情境提供者记下的 Windows 内部事件)不会转进 pcapng。若也要事件,用 netsh trace convert input=C:\temp\nettrace.etl 转成文字等,或在 Windows Performance Analyzer 开启 ETL。57
flowchart TB
accTitle: 读 netsh trace ETL 分成两条路
accDescr: ETL 里的数据包用 etl2pcapng 转成 pcapng 在 Wireshark 读;ETW 事件不转成 pcapng,因此用 netsh trace convert 或 Windows Performance Analyzer 读
etl["netsh trace ETL"] --> pk["数据包"]
etl --> ev["ETW 事件"]
pk -->|etl2pcapng| pc["转成 pcapng"]
pc --> ws["在 Wireshark 读"]
pc -.-> pid["进程 ID 留在注解"]
ev -.-> no["不转成 pcapng"]
no --> alt["用 convert 或 WPA 读"]
图 8: ETL 里的数据包转成 pcapng 来读;ETW 事件用另一种方式读。
5. 在 Wireshark 读的第一步 — 显示过滤器与 TCP 分析
打开 pcapng 后,先用显示过滤器切掉杂讯。常用的列在表里。1213
| 显示过滤器 | 意义 |
|---|---|
ip.addr == 192.168.10.20 |
这个 IP 是来源或目的地的数据包 |
tcp.port == 8443 |
涉及这个 TCP 连接埠的数据包 |
dns |
只看 DNS 查询与回应 |
tcp.flags.syn == 1 && tcp.flags.ack == 0 |
只看连接 SYN |
tcp.flags.reset == 1 |
只看 RST(强制切断) |
tcp.analysis.retransmission |
Wireshark 判断为重传的数据包 |
tcp.analysis.zero_window |
接收视窗 0(接收端不能再收) |
tcp.analysis.flags |
侦测到某种问题的所有数据包 |
tcp.analysis.* 是 Wireshark 追踪 TCP 序号后贴上的分析旗标。重传、重复 ACK、乱序、ZeroWindow 等会被机械地抓出,所以 读档的标准起手是先输入 tcp.analysis.flags,列出「看起来有问题」的地方。13
超时调查时,依序找下列形状。
- 三次握手完成了吗? SYN → SYN/ACK → ACK 三个数据包都在吗?SYN 重复且没有回复,就是没到达对端,或在中途被默默丢掉(典型防火墙模式)。
- 哪一边送出 RST? 对 SYN 立刻 RST 代表目的连接埠没人在听;连接建立后的 RST 代表一边强制切断。RST 的来源 IP 就是「谁切断」的直接证据。
- 重传是否持续? 同一区段反复重传,代表 确认(ACK)没回到传送端。出去的资料丢了还是回来的 ACK 丢了,单侧捕获无法了结(所以下一章「两边捕获」很重要)。重传与超时在「TCP 重传导致工业相机通信中断的原因与排查」有更深入说明。
- 有没有 ZeroWindow? 那是接收应用程序没从通信端读取、接收缓冲区满了的迹象。该怀疑的是接收应用程序的设计(「TCP 中「发送单位=接收单位」的误区」),而不是网络。
flowchart TB
accTitle: 超时调查要找的形状顺序
accDescr: 确认三次握手是否完成、RST 是否存在及其来源、重传是否持续,再看 ZeroWindow,对原因做第一标记
hs{"SYN 有回复吗?"} -->|否| ng["从未到达(典型防火墙)"]
hs -->|是| rs{"有 RST 吗?"}
rs -->|是| who["RST 来源切断了它"]
rs -->|否| rt{"重传持续吗?"}
rt -->|是| ack["ACK 没回来"]
rt -->|否| zw{"有 ZeroWindow 吗?"}
zw -->|是| app["接收端没在读"]
图 9: 依序找握手、RST、重传、ZeroWindow,就能缩小下一步要看的地方。
逐包读之前,先用统计功能抓住全貌也有帮助。[Statistics] → [Conversations] 是「哪一对 IP/连接埠、从何时到何时、多少量」的清单,可先找出关心的通信再只筛那一条。[Statistics] → [I/O Graph] 是随时间变化的流量图,「从这个时间起有一边沉默」这种形状会跳出来。对关心的 TCP 通信按右键选 [Follow] → [TCP Stream],就能把该连接的往来当明文通读。
flowchart TB
accTitle: 先用统计抓住图像,再缩小到一条通信
accDescr: 在 Conversations 列出哪些通信何时走了多少,从 I/O Graph 抓住沉默区间,筛到关心的通信,再当 TCP 串流通读
ov["用统计抓住全貌"] --> cv["Conversations 的通信清单"]
ov --> io["在 I/O Graph 看流量"]
cv --> flt["筛到关心的通信"]
io -.-> mute["沉默区间变得可见"]
flt --> fs["当 TCP 串流通读"]
图 10: 逐包读之前,先用统计抓住图像,缩小到关心的通信,再通读。
6. 回环陷阱 — 打到 localhost 的流量从不经过 NIC
调查同一台电脑上应用程序之间的通信——例如业务应用程序连到 localhost:8080 的中间服务——却卡在「Wireshark 什么都没有」,是经典陷阱。
原因很清楚。打到 localhost(127.0.0.1)的流量不会经过物理 NIC,而是在操作系统内部回环路径折返。 以物理网卡为目标的一般捕获因此从头就看不到。9
flowchart TB
accTitle: 为什么打到 localhost 的流量不出现在捕获
accDescr: 打到 localhost 的流量不经过物理 NIC,在操作系统内部回环路径折返,因此以物理网卡为目标的一般捕获看不到
app["应用程序"] --> stack["网络堆栈"]
stack -->|外部| nic["物理 NIC"]
nic --> seen["一般捕获看得到"]
stack -->|localhost| lo["在操作系统内折返"]
lo -.-> miss["一般捕获没有"]
lo -.-> alt["Npcap 回环 或 pktmon"]
图 11: 打到 localhost 的流量在 NIC 前折返,物理网卡捕获看不到。
应对有两种。
- 用 Wireshark 捕获时:把捕获目标选成 Npcap 的 「Adapter for loopback traffic capture」。Windows 版 Wireshark 安装程序(3.0 以后)内含 Npcap,已安装 Wireshark 就不必再多做。9
- 用内置工具捕获时:pktmon 不是在 NIC 外侧,而是在网络堆栈内多个点捕获4,所以也能观察回环流量。为求确定,设正式等待重现之前,先在该机器用
pktmon start -c -m real-time即时显示确认关心的回环流量真的看得到。
也要小心两种混淆。
- 「localhost」可能解析成 IPv6 ::1。 应用程序连到 IPv6 ::1,调查者只看 127.0.0.1(IPv4),就误判「没有流量」。把显示过滤器拉到两边,例如
ip.addr == 127.0.0.1 || ipv6.addr == ::1,或把应用程序目的地设成明确地址。9 - 打到自己真实 IP 的流量也不会上线。 同一台电脑从 192.168.10.5 连到 192.168.10.5 时,目的地是真实 IP,操作系统仍在内部折返。「指定了真实 IP,就一定经过 NIC」并没有保证。
flowchart TB
accTitle: localhost 解析成 IPv6 时的混淆
accDescr: 应用程序的 localhost 可能解析成 IPv6 ::1,调查者只看 127.0.0.1 会误判没有流量,因此把显示过滤器拉到两个地址,或把目的地确认成明确地址
app["应用程序连到 localhost"] --> v6["实际解析成 ::1(IPv6)"]
look["调查者只看 127.0.0.1"] --> none["画面上什么都没有"]
v6 --> none
none --> fix1["把过滤器拉到两个地址"]
none --> fix2["把目的地设成明确地址"]
图 12: 小心 localhost 解析成 ::1、只看 127.0.0.1 就以为「没有流量」的混淆。
7. 在哪里捕获 — 单侧、双侧与时钟同步
捕获的价值由「在哪里捕获」决定。经验规则如下。
| 捕获位置 | 能知道什么 | 何时适合 |
|---|---|---|
| 只在用户端 | 你送出什么、回来什么 | 先抓全貌。不能碰服务器时 |
| 只在服务器 | 要求是否到达、是否送出回应 | 用户端很多,或无法指定一台时 |
| 两边同时 | 路径上哪里丢了数据包、哪一边沉默 | 需要厘清责任边界时 |
单侧捕获只告诉你「从我这个位置看到的事实」。用户端持续重传,分不出是送出的数据包在路径上消失,还是到了服务器而回复消失。两边捕获并排起来,就能厘清「用户端送了/服务器从没收到」——哪一边沉默。 需要厘清责任边界(应用程序、操作系统、网络装置或对端)时,值得一开始就安排双侧捕获。
flowchart TB
accTitle: 单侧与双侧捕获能告诉你什么
accDescr: 单侧捕获无法分辨是出去的数据包消失还是回来的回复消失;两边捕获并排起来,才能厘清哪一边沉默
one["在单侧捕获"] --> fact["自己这一侧的事实"]
fact --> und["出去还是回来?"]
both["在两边捕获"] --> mt["并排起来"]
mt --> fix["哪一边沉默"]
mt -.-> pre["需要时钟同步"]
图 13: 单侧只显示你看到的事实;两边并排,责任边界才第一次能厘清。
7.1. 对照的前提是时钟同步
要把两边捕获并排,两台机器的时钟必须一致。开始捕获前,检查并记录时钟偏差。
:: Check time-sync status (sync source, last sync time)
w32tm /query /status
:: Measure the offset against the peer server (5 samples)
w32tm /stripchart /computer:sv-app01 /dataonly /samples:5
w32tm /stripchart 显示你与对端电脑的时间偏差,并排捕获时可作为「服务器时钟快了 +0.8 秒」这类校正的依据。14 偏差很大的环境,先修好时间同步再捕获,最后反而比较短。
flowchart TB
accTitle: 对照前检查时钟偏差的步骤
accDescr: 用 w32tm 确认自己的时间同步状态,用 stripchart 测量并记录与对端服务器的偏差,对照时作为校正依据;偏差大就先修好同步再捕获
st["用 query 确认同步状态"] --> mc["用 stripchart 测量偏差"]
mc --> rc["记录偏差"]
rc --> use["对照时校正的依据"]
mc -.-> big["偏差大就先修好同步"]
图 14: 捕获前测量并记录时钟偏差,并排时作为校正依据。
7.2. 「不知道何时会发生」时 — 环形缓冲
重现条件不明的故障,基本作法是让环形缓冲一直跑,故障发生时再停。
- pktmon:预设就是 circular 模式。用
--file-size设上限(MB);较旧的数据包会被覆写。8 - netsh trace:指定为
maxSize=1024 filemode=circular。5 - Wireshark:在 [Capture] → [Options] → [Output] 可设定「多个文件 + 环形缓冲」。依文件大小或时间轮替,只保留最新 N 个档,因此能在磁碟用量上限下长跑。15
无论哪一种,都要与现场人员约定:故障发生时,「先记下时间,然后」再停止捕获。环形缓冲等越久就越抹掉过去,从发生到停止的路径一长,关心的区间就被覆写。
flowchart TB
accTitle: 用环形缓冲捕获等待
accDescr: 重现条件不明的故障就让环形缓冲一直跑,故障发生时记下时间并立刻停止;停晚了,较旧的数据包被覆写,关心的区间就消失
st["开始环形缓冲捕获"] --> wt["让它跑著等"]
wt --> ev["故障发生"]
ev --> memo["记下时间"]
memo --> sp["立刻停止"]
wt -.-> ow["较旧的数据包被覆写"]
ow -.-> late["停晚会抹掉关心的区间"]
图 15: 环形缓冲等越久就越抹掉过去,记下时间后立刻停止。
8. TLS 藏起载荷的问题 — 仍然看得到什么
现在多数业务流量是 TLS(HTTPS)。人们容易觉得「加密了捕获就没意义」,但 超时调查想知道的大多数,让加密维持原样仍看得见。
- TCP 连接是否建立(三次握手)
- TLS 握手走到哪——ClientHello 有没有 ServerHello 回来、握手中是否被 RST 或 alert 切断
- ClientHello 上的目的地主机名称(SNI),以及协商的 TLS 版本
- 连接起来后哪一边停止传送。沉默的位置、重传、RST,或干净关闭(FIN)
也就是隔离「连不上」、「中途断掉」、「没有回应回来」,几乎不需要解密载荷。加密失去的是「他们说了什么」;「谁在何时沉默」仍在。
flowchart TB
accTitle: TLS 捕获能看到与看不到的
accDescr: 加密只藏起应用程序资料载荷;TCP 连接建立、TLS 握手成败、SNI 与 TLS 版本、RST、哪一边沉默,让加密维持原样仍看得见
tls["TLS 流量捕获"] --> vis["看得见"]
tls --> hid["看不见"]
vis --> v1["TCP 连接建立"]
vis --> v2["TLS 结果与 SNI"]
vis --> v3["RST/谁沉默"]
hid --> h1["应用程序资料载荷"]
图 16: 加密只失去载荷;通信骨架让 TLS 维持原样仍可读。
仍需要载荷时,Wireshark 可用 SSLKEYLOGFILE 环境变数写出的会话密钥解密 TLS。支持限于 Firefox、Chrome、以 Chromium 为基础的 Edge、OpenSSL 系列库等部分实现;Windows 内置 SChannel(使用 WinHTTP 或 WinINET 的应用程序)不支持这个机制。10 「会话密钥写到文件」代表拿到该档的人能解密整段通信,这不是正式环境手法;请当成开发环境的重现与除错。
flowchart TB
accTitle: SSLKEYLOGFILE 解密的运作与限制
accDescr: 经 SSLKEYLOGFILE 写出的会话密钥可让 Wireshark 解密 TLS,但只有 Firefox、Chrome 系列等部分实现支持,SChannel 不支持;拿到密钥档的人就能解密通信,因此当成仅限开发环境的手法
env["设定 SSLKEYLOGFILE"] --> key["写出会话密钥"]
key --> ws["在 Wireshark 读"]
key -.-> risk["持有密钥者可解密"]
risk -.-> dev["仅限开发"]
env -.-> sup["仅部分 TLS 堆栈"]
sup -.-> sch["SChannel:不支持"]
图 17: 写出会话密钥就能解密,但支持的实现有限,密钥的性质也让它只能当开发环境手法。
流量经过内部 Proxy 时,捕获里出现的目的地是 Proxy 服务器,TLS 走在 CONNECT 隧道里。应用程序到底朝哪个 Proxy 去,这个先决问题整理在同日的搭配文章「企业 Proxy 与 Windows 应用程序 — 厘清 WinINET、WinHTTP、.NET 的 Proxy 解析」。
9. 与应用程序日志对照 — 把时间放在同一轴
单靠捕获很少得出结论。实务上决定性的一步是 把应用程序日志的一行与数据包的一趟往返放在同一时间轴。
步骤如下。
- 从应用程序日志找出故障时间(例如 10:23:41 的超时例外)。若超时值是 30 秒,开始应在 10:23:11 附近。
- 把 Wireshark 的时间显示改成 [View] → [Time Display Format] → [Date and Time of Day],再用显示过滤器缩小区间(也能用时间筛选,例如
frame.time >= "2026-08-20 10:23:00" && frame.time <= "2026-08-20 10:24:00")。 - 在该区间依第 5 章顺序确认(握手 → RST → 重传 → ZeroWindow)。若能对到「日志超时时间的 30 秒前送出 SYN,之后只有 SYN 重传」,日志里的「超时」就换成观察「在这个捕获点,完全没有回复回来」(SYN 没到达对端,还是回来的 SYN/ACK 在回程遗失,单靠这个捕获点无法厘清。要厘清就在服务器捕获并排起来)。
- 一定要校正捕获时间与日志时间的偏差(第 7.1 节量到的时钟偏差,以及日志的时区标记)。几秒的对照误差会把错的通信钉成元凶。
flowchart TB
accTitle: 把应用程序日志与数据包并排的步骤
accDescr: 从应用程序日志找出故障时间,用超时值反推开始时间,在 Wireshark 用显示过滤器缩小区间,依序确认形状,校正时钟偏差,放在同一时间轴
lg["1. 从日志找出故障时间"] --> rev["用超时值反推开始"]
rev --> flt["2. 用显示过滤器缩小区间"]
flt --> chk["3. 依第 5 章顺序确认形状"]
chk --> adj["4. 校正时钟偏差"]
adj --> done["日志的一句话变成观察"]
图 18: 从日志时间缩小区间,确认形状,校正时钟偏差,放在同一轴。
把调查结果交给第三者(厂商、电信业者、客户网络人员)时,交出前用过滤器切掉杂讯既是礼貌也是安全措施。在 Wireshark 用显示过滤器缩小到关心的通信,再用 [File] → [Export Specified Packets] 储存「只含显示的数据包」,就得到只要该范围的小 pcapng。
最后是处理注意。捕获文件就是通信本身。 可能含明文协议的认证信息、HTTP Cookie 与 API 密钥、邮件或报表内容、个人资料。下列三点请与捕获程序成套决定。
- 最小必要捕获:用捕获前过滤器(第 3、4 章)缩小目标,时间窗尽量短。不要在客户环境「先全部捕获再说」
- 交出前缩小:只导出关心的通信,不要带无关的第三者流量。若仍有敏感部分,与对方约定遮罩或另途
- 保存与删除:决定捕获文件放哪、放多久、何时删除,调查结束就删
flowchart TB
accTitle: 交出捕获文件前要决定的三件事
accDescr: 捕获就是通信本身,因此与捕获程序成套决定:用捕获前过滤器与时间窗缩到最小、交出前只抽出关心的通信以免带入无关流量、决定保存位置与期间并在调查后删除
cap["捕获 = 流量"] --> p1["捕获最小范围"]
cap --> p2["先抽出目标"]
cap --> p3["设定保存并删除"]
p2 -.-> exp["筛选并导出"]
图 19: 把最小捕获、交出前缩小、保存与删除与捕获程序成套决定。
10. 总结
- 应用程序日志「超时」的下一层,是实际走过线路的数据包事实。SYN 没有回复、被 RST 切断、重传持续、或出现 ZeroWindow,会改变下一步要看的地方。
- 即使现场不能安装 Wireshark,也能用 Windows 内置的 pktmon 与 netsh trace 捕获。用内置工具捕获、用自己机器的 Wireshark 读——这个分工是基本型。
- pktmon 是四步:注册过滤器 →
pktmon start --capture→pktmon stop→pktmon etl2pcap。预设截成 128 字节,要载荷别忘了--pkt-size 0。看到丢弃位置与原因是只有 pktmon 才有的长处。 - netsh trace 把一组 ETW 提供者当情境捕获,加上
persistent=yes就能撑过重启。用 etl2pcapng 把 ETL 转成 pcapng 来读。 - 在 Wireshark 从
tcp.analysis.flags开始,依序找握手、RST、重传、ZeroWindow。先用 Conversations 与 I/O Graph 抓住图像再缩小会更快。 - 打到 localhost 的流量不经过 NIC,一般方法捕获不到。用 Npcap 的回环网卡或 pktmon 的堆栈内捕获。
- 两边捕获并排,「哪一边沉默」就能厘清。前提是时钟同步(w32tm)。重现条件不明的故障,用环形缓冲等待。
- 即使在 TLS 下,通信骨架仍可见。把解密(SSLKEYLOGFILE)当成仅限开发环境的手法,把捕获文件本身当机密:把最小捕获、缩小范围、删除写进作业。
数据包捕获常被当成「网络专家的工具」,实务上它是 只有与应用程序日志并排才开始有意义的应用程序侧调查工具。下次调查停在「超时」一句话时,去看下一层。
相关文章
- TCP 重传导致工业相机通信中断的原因与排查
- TCP 中「发送单位=接收单位」的误区 ── 用字节流思维设计接收端,避免拆包与粘包
- 把OSI参考模型彻底看懂 ── 拆解一个HTTP请求里的七层结构
- Process Monitor(ProcMon)实战指南 —— 10 分钟定位「配置未生效」「ACCESS DENIED」问题
- Windows 防火墙与业务应用 ── 入站规则要通过安装程序注册
- 企业 Proxy 与 Windows 应用程序 — 厘清 WinINET、WinHTTP、.NET 的 Proxy 解析
相关咨询领域
小村软件有限公司承接「业务应用程序通信偶尔失败、找不到原因」、「只想隔离出只在客户环境发生的连接错误」这类源自通信的故障调查。捕获设计(在哪里、捕获什么、捕获多少)、Wireshark 分析、与应用程序日志对照、以及应用程序侧修正,我们当成一连串工作处理。
参考链接
-
Microsoft Learn, pktmon etl2pcap. 说明把 pktmon ETL 日志转成 pcapng 以便在 Wireshark 等工具分析;pcapng 会失去丢弃信息与堆栈内捕获点信息,因此转换前应先用 –drop-only 或 –component-id 缩小。 ↩ ↩2 ↩3 ↩4
-
GitHub, microsoft/etl2pcapng. 说明 etl2pcapng 是 Microsoft 的开源工具,把以 netsh trace start capture=yes 等捕获的 ETL 档内数据包转成 pcapng,保留介面信息并把进程 ID 写成数据包注解。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Pktmon command formatting. 说明 pktmon.exe 可用于 Windows 10 与 Windows Server 2019(版本 1809)以后;快速开始步骤为注册过滤器 → 开始 → 重现 → 检查计数器 → 停止并转换;过滤器最多 32 个、以 OR 结合、不区分来源与目的地;文字输出中被丢弃的数据包带有 dropReason。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Packet Monitor (Pktmon). 说明 Packet Monitor 是 Windows 内置的跨组件诊断工具;在网络堆栈内多个点捕获数据包以可视化路径;在支持的组件以丢弃原因(MTU Mismatch、Filtered VLAN 等)报告丢弃;并提供各点的数据包计数器。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, netsh trace. 说明 netsh trace start 的参数,如 scenario、capture、tracefile、maxSize、fileMode(circular 作为环形缓冲)、persistent(跨重启维持会话),以及用 netsh trace convert 把 ETL 转成文字等。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Using Netsh to manage traces. 说明情境是为故障排除预先定义的提供者集合;用 netsh trace show scenarios / show scenario 检查;同一时间只能跑一个追踪会话;capture=yes 时的 ipv4.address 等数据包过滤器;停止会产生 ETL 与含系统信息的 .cab。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Diagnose packet loss. 说明官方调查程序:先用 pktmon 捕获追踪并检查本机丢弃原因与统计,结合 Wireshark 的协议层分析,不够再进到 netsh trace 情境的组件层追踪。 ↩ ↩2 ↩3
-
Microsoft Learn, pktmon start. 说明用 –capture 开始捕获;–pkt-size 预设 128 字节、0 记录整个数据包;–file-name 与 –file-size(预设 512MB);以及 –log-mode 值(circular、multi-file、real-time、memory),circular 为预设。 ↩ ↩2 ↩3 ↩4
-
Wireshark Wiki, CaptureSetup/Loopback. 说明在 Windows 以物理 NIC 为目标的一般捕获无法捕获打到 127.0.0.1 的回环流量;Npcap 的「Adapter for loopback traffic capture」使回环捕获成为可能;Wireshark 3.0 以后的 Windows 安装程序内含 Npcap。 ↩ ↩2 ↩3 ↩4
-
Wireshark Wiki, TLS. 说明 Wireshark 可用 SSLKEYLOGFILE 环境变数写出的会话密钥解密 TLS;支持涵盖 Firefox、Chrome、以 Chromium 为基础的 Edge、OpenSSL 系列库等;Microsoft SChannel 不支持这个机制。 ↩ ↩2
-
Microsoft Learn, pktmon counters. 说明 pktmon counters 显示各监视组件的通过与丢弃计数;–drop-reason 显示各丢弃计数最近一次丢弃原因;以及用 –live 即时更新。 ↩
-
Wireshark, Building Display Filter Expressions (Wireshark User’s Guide). 说明显示过滤器语法、ip.addr 与 tcp.port 等栏位指定、比较运算子,以及用 and/or/not 组合。 ↩
-
Wireshark, TCP Analysis (Wireshark User’s Guide). 说明 Wireshark TCP 分析旗标清单(tcp.analysis.retransmission、tcp.analysis.duplicate_ack、tcp.analysis.out_of_order、tcp.analysis.zero_window 等)与各旗标被指定的条件。 ↩ ↩2
-
Microsoft Learn, Windows Time service tools and settings. 说明 w32tm 是设定、监视与故障排除 W32Time 的建议命令列工具,以及 w32tm /stripchart 显示你与对端电脑的时间偏差(/dataonly、/samples 等选项)。 ↩
-
Wireshark, Capture files and file modes (Wireshark User’s Guide). 说明捕获文件输出模式(单一档、多档、环形缓冲),以及环形缓冲只保留最新资料以便限制磁碟用量。 ↩
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
把OSI参考模型彻底看懂 ── 拆解一个HTTP请求里的七层结构
本文不靠死记硬背来理解OSI参考模型,而是从实物出发。用C#组装出一个承载HTTP GET请求的Ethernet帧并进行解剖,通过十六进制转储和Wireshark确认L2〜L7如何以字节序列的形式层层物理嵌套在一起。文章从实务角度梳理各层与.NET API(HttpClie...
OneDrive「按需文件」与业务应用 ── 占位符打破的前提与对策
桌面 CSV 打不开、导入以「找不到文件」失败,原因可能是 OneDrive 的已知文件夹搬移与按需文件。本文说明占位符的运作、如何用属性判断状态,以及应用与 IT 各自能做的事。
企业内部代理与 Windows 应用 ── 理清 WinINET、WinHTTP、.NET 的代理解析
浏览器能连上,只有业务应用过不了企业内部代理。原因多半是 WinINET、WinHTTP、环境变量与 .NET 各自读取的代理设置不一致。本文整理 PAC 与 WPAD、认证代理、TLS 检查与隔离步骤。
解读 Windows 错误码 ── Win32、HRESULT、NTSTATUS 三层结构
出现 0x80004005 时,先分解再搜索。本文整理 Win32 错误、HRESULT、NTSTATUS 的三层结构、0x8007xxxx 是包起来的 Win32 错误这个最重要模式,以及用 err.exe 与 PowerShell 查询的方法。
Windows的「内存使用量」究竟表示什么 ── 正确解读 Working Set・Private Bytes・Commit・页面文件
任务管理器中的内存、Working Set、Private Bytes、Commit并不是同一个值。本文讲解Windows虚拟内存与物理内存的关系、页面文件的作用,以及在排查内存不足或泄漏时应该关注的指标。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
故障调查 & 长期运行故障
整理间歇性故障、通信诊断、长期运行崩溃、失败路径测试基础的主题页面。
与本主题相关的服务
本文与以下服务页面相关联,欢迎从最接近的入口查看。
Windows 应用程序开发
支持包含常驻处理、设备联动、运行日志与可维护结构的 Windows 桌面应用程序。
故障调查 & 根本原因分析
调查难以复现的故障、长时间运行后的问题、内存泄漏、通信停滞等棘手的生产环境问题。
常见问题
汇总了咨询这一主题时常见的问题。
- 客户服务器不能安装 Wireshark 时,要怎么捕获数据包?
- 用 Windows 内置的 pktmon 或 netsh trace,不必再装软件就能捕获。pktmon 在提升权限的终端注册过滤器,用 pktmon start --capture 开始捕获,再用 pktmon stop 停止。得到的 ETL 可用 pktmon etl2pcap 转成 pcapng,分析带回自己电脑的 Wireshark 即可。「用内置工具捕获、用 Wireshark 读」是安装受限现场的基本分工。
- 该用 pktmon 还是 netsh trace?
- 操作系统有 pktmon(Windows 10 / Windows Server 2019 以后)就先用 pktmon。指令单纯,能看到网络堆栈哪个组件丢了数据包(丢弃原因),pcapng 转换也自成一体。netsh trace 较适合在没有 pktmon 的旧系统捕获、要把 Windows 组件的 ETW 事件当情境一次收集、或要用 persistent=yes 让捕获撑过重启时。Microsoft 自己的故障排除资料也指向这个顺序:先 pktmon,不够再用 netsh trace。
- 为什么打到 localhost(127.0.0.1)的流量在 Wireshark 看不到?
- 打到 localhost 的流量不会经过物理 NIC,而是在操作系统内部回环路径折返。以物理网卡为目标的一般捕获因此从头就看不到。在 Wireshark 选 Npcap 的「Adapter for loopback traffic capture」就能捕获回环流量。pktmon 在网络堆栈内捕获,所以也能观察回环流量。另一个常见混淆是「localhost」解析成 IPv6 的 ::1,只盯着 127.0.0.1 的画面就什么都没有——请明确指定地址来确认。
- 数据包捕获能看到 HTTPS(TLS)通信的内容吗?
- 应用程序资料的载荷已加密,看不到。但 TCP 连接与切断、TLS 握手成败、RST 切断、哪一边停止回应这些「通信骨架」即使加密仍可见,多数超时调查可以让 TLS 维持加密继续做。若需要载荷,可用 SSLKEYLOGFILE 解密,但只有 Firefox、Chrome 系列等部分 TLS 实现支持;Windows 内置 SChannel 不支持。这会把密钥材料写出文件,请当成仅限开发环境的选项。
- 把捕获文件寄给外部支持窗口安全吗?
- 原样寄出很危险。捕获文件就是通信本身,可能含明文协议的认证信息、Cookie、API 密钥与个人资料。先在捕获时用过滤器与时间窗缩到最小必要,交出前再用 Wireshark 显示过滤器只抽出目标通信并导出。剩下的敏感部分,先与对方约定处理方式(遮罩或另途交付)再寄。捕获文件要保存多久、何时删除,也请事先决定。