做网络协议实验时,最直接的方案是打开 Wireshark,选择一个网卡,看着数据包滚过屏幕。工具很好用,但它不会解释一个数据包怎样从网卡进入程序,怎样被识别成 IPv4,又怎样变成协议树和十六进制视图。
我想把这个过程完整走一遍,于是用 C++17、Win32 和 Npcap 做了一个轻量网络分析器 NetObserver。
项目没有试图复刻 Wireshark。它的目标更具体:完成网卡枚举、实时捕获、BPF 过滤、协议解析、捕获后过滤、TCP 会话重组、pcapng 保存和读取,并提供一个可操作的图形界面。
基本是借助AI开发,所以除上述目的,还可以将之作为AI赋能的项目经验。
1. 安装 Windows 开发环境
下列都是一些比较简单的安装,就不一一提供下载链接和安装步骤了
安装:
- Visual Studio 2022 Build Tools
- 工作负载:使用 C++ 的桌面开发
- CMake
- Git
- VS Code
- Wireshark
- Python,仅用于测试本地 HTTP 服务
验证:
cmake –version
git –version

VS Code 只是编辑器,编译由 MSVC 和 CMake 完成。
2. 安装 Npcap
安装 Npcap 运行库,建议选择:
Install Npcap in WinPcap API-compatible Mode
验证:
Get-Service Npcap

USB 抓包组件不是本实验必需项。
3. 准备 Npcap SDK
下载 Npcap SDK,并放到:
third_party\\npcap-sdk
验证:要均返回true
Test-Path "D:\\AI\\NetObserver\\third_party\\npcap-sdk\\Include\\pcap.h"
Test-Path "D:\\AI\\NetObserver\\third_party\\npcap-sdk\\Lib\\x64\\wpcap.lib"

目录应包含:
third_party\\npcap-sdk\\Include\\pcap.h
third_party\\npcap-sdk\\Lib\\x64\\wpcap.lib
third_party\\npcap-sdk\\Lib\\x64\\Packet.lib
不要把 SDK 二进制提交到 Git。
4. 建立空项目
例如:(命名自己想)
D:\\AI\\NetObserverLab
推荐结构:
NetObserverLab/
├── CMakeLists.txt
├── CMakePresets.json
├── src/
│ ├── core/
│ │ ├── CaptureEngine.h
│ │ ├── CaptureEngine.cpp
│ │ ├── PacketTypes.h
│ │ ├── PacketParser.h
│ │ └── PacketParser.cpp
│ ├── console_main.cpp
│ └── gui_main.cpp
├── tests/
├── scripts/
├── resources/
└── README.md
5. 创建基础 .gitignore
需要建立一个git仓库,可以让你开发的时候,回溯版本,很有用
至少忽略:
build/
.vs/
third_party/npcap-sdk/
captures/
*.pcap
*.pcapng
防止你的git仓库爆炸
下面就是具体步骤,可以将文章发给AI,辅助理解开发
6. 建立最小 CMake 工程
先只创建控制台目标,暂时不写 GUI。
CMake 需要找到 Npcap SDK:
find_path(PCAP_INCLUDE_DIR
NAMES pcap.h
HINTS "${CMAKE_SOURCE_DIR}/third_party/npcap-sdk"
PATH_SUFFIXES Include
)
find_library(WPCAP_LIBRARY
NAMES wpcap
HINTS "${CMAKE_SOURCE_DIR}/third_party/npcap-sdk"
PATH_SUFFIXES Lib/x64
)
链接:
target_include_directories(netobserver_core PUBLIC
"${CMAKE_SOURCE_DIR}/src"
"${PCAP_INCLUDE_DIR}"
)
target_link_libraries(netobserver_core PUBLIC
"${WPCAP_LIBRARY}"
ws2_32
)
在源文件中加入:
#define WPCAP
#define HAVE_REMOTE
#include <pcap.h>
使用 CMake 生成 Visual Studio 工程:
cmake -S . -B build -A x64
cmake –build build –config Debug


这个阶段不要先写界面。先保证 C++ 和 Npcap 能够链接成功。
7. 枚举网卡
第一项功能是列出所有抓包设备。
核心调用:
pcap_findalldevs
pcap_freealldevs
控制台输出网卡名称和描述。结果中一般可以看到:
Realtek Wireless LAN
Bluetooth Device
VMware Virtual Ethernet Adapter
Adapter for loopback traffic capture
运行:
.\\build\\Debug\\netobserver-cli.exe –list

如果能看到 \\Device\\NPF_…,说明 Npcap 和程序配置正常。
当前联网流量一般选择 Wi-Fi 或有线网卡。测试本地 HTTP 服务时选择回环网卡。
8. 打开网卡并抓包
选择网卡后调用:
pcap_open_live(
deviceName,
65535,
1,
1000,
errbuf
);
参数依次是网卡名称、捕获长度、混杂模式和读取超时。
循环调用:
pcap_next_ex
拿到数据后至少显示:
- 数据包序号
- 捕获长度
- 原始长度
必须复制数据内容:
std::vector<std::uint8_t> bytes(
rawPacket,
rawPacket + packetHeader->caplen
);
pkt_data 指向的缓冲区会被下一次捕获复用,不能直接保存这个指针。
为了及时响应停止操作,可以开启非阻塞读取:
pcap_setnonblock(handle, 1, errbuf);
停止时:
pcap_breakloop(handle);
pcap_close(handle);
9. 设置 BPF 捕获过滤
使用:
pcap_lookupnet
pcap_compile
pcap_setfilter
pcap_freecode
可以先支持这些表达式:
tcp
udp
icmp
arp
udp port 53
tcp port 8080
host 10.122.60.186
捕获过滤在 Npcap 层生效,不匹配的数据包不会被程序读取。
10. 解析 Ethernet 和 IP
以太网帧开头包括:
目的 MAC:6 字节
源 MAC:6 字节
EtherType:2 字节
接着解析 IPv4:
- 版本和首部长度
- 总长度
- TTL
- 协议号
- 源 IP
- 目的 IP
IP 首部长度不能固定写成 20:
const std::size_t ipHeaderLength =
(ipHeader->verIhl & 0x0F) * 4;
传输层偏移:
const std::size_t l4Offset =
ethernetHeaderLength + ipHeaderLength;
端口和地址需要转换字节序:
ntohs
ntohl
协议解析前必须检查 caplen,不能让短包或畸形包造成越界读取。
11. 解析 TCP、UDP、ARP、ICMP 和 IGMP
建议按以下顺序实现:
UDP
→ TCP
→ ICMP
→ ARP
→ IGMP
TCP 至少解析:
- 源端口、目的端口
- 序列号、确认号
- 首部长度
- SYN、ACK、FIN、RST、PSH、URG
- 应用层载荷偏移
UDP 解析端口、长度和载荷。ARP 解析请求、应答和发送方/目标 MAC、IP。ICMP 识别 Echo Request 和 Echo Reply。IGMP 可以先处理常见成员关系报文。
命令行输出示例:
[1] 10.0.0.1:50000 -> 10.0.0.2:80 TCP
[2] 10.0.0.1 -> 10.0.0.2 ICMP Echo Request
[3] Who has 10.0.0.20? Tell 10.0.0.10
12. 分析 HTTP 或 FTP
选择 HTTP 作为重点应用层协议。
在 TCP 载荷中检查:
GET /
POST /
HEAD /
HTTP/
可以提取:
- 请求方法
- URI
- Host
- Content-Type
- HTTP 状态码
FTP 则可以先分析 21 端口的命令和响应首行。
这个阶段只分析单个数据包中的应用层文本,不要求立即实现完整 HTTP 流解析。
13. 加入多线程 GUI
GUI 建议先使用 Win32,避免引入 MFC 或 Qt 的额外配置。
界面大致分为:
顶部:网卡、捕获过滤、开始、停止
左侧:快捷过滤和实时统计
中间:数据包列表
右侧下方:协议详情、十六进制、会话统计
捕获线程只负责读取数据包。数据解析后通过消息交给主线程:
PostMessage(hWnd, WM_APP_PACKET, 0, (LPARAM)packet);
不要在捕获线程中直接操作窗口控件。
高流量下不要每个包发送一次消息,可以每 64 个包组成一批。否则消息队列会堆积,停止按钮可能很久才响应。
14. 实现捕获后显示过滤
捕获过滤和显示过滤要分成两个输入框。
例如:
BPF 捕获过滤:icmp
显示过滤:tcp and tcp.port == 80
显示过滤只改变已捕获的数据包列表,不影响 pcapng 文件。
可以先实现这些条件:
icmp
tcp
udp
arp
ip.addr == 192.168.1.10
tcp.port == 80
udp.port == 53
frame.len > 100
再增加 and、or、not 和括号。
“仅此会话”按钮可以根据当前数据包自动生成地址和端口条件。
15. 保存 pcap 或 pcapng
第一版可以直接使用 libpcap 保存经典 pcap:
pcap_dump_open
pcap_dump
pcap_dump_close
后续实现 pcapng 时,需要写入:
- Section Header Block
- Interface Description Block
- Enhanced Packet Block
保存后先用 capinfos 检查文件:
capinfos capture.pcapng
然后直接用 Wireshark 打开。如果 Wireshark 能正常读取数据包数量和时间戳,说明文件结构基本正确。
16. 实现 TCP 会话和 Follow Stream
TCP Follow Stream 不是简单拼接载荷。
需要处理:
- 双向 TCP 连接
- 序列号
- 乱序段
- 重传段
- 部分重叠
- 序列号回绕
程序可以按两个端点建立会话,分别保存两个方向的数据。遇到重复段时跳过,遇到乱序段时进入待处理缓存。
流内容不能无限增长。可以限制每个方向最多保留 1 MB,同时设置全局内存上限。
明文文本直接显示。TLS、压缩数据和二进制内容显示十六进制预览,不要强行当作文本展示。
17. 测试和 Wireshark 对比
真实流量按以下顺序测试:
ICMP
→ ARP
→ DNS
→ TCP
→ HTTP
→ Follow Stream
保存 pcapng 后,用 Wireshark 打开同一个文件,对比:
- 源、目的 MAC
- 源、目的 IP
- 协议
- 源、目的端口
- 数据包长度
- TCP 标志位
- ICMP 类型
- 原始载荷
Wireshark 中选择:
Follow → TCP Stream → Hex Dump
就能对比同一个 TCP 流的十六进制内容。
理:
- 双向 TCP 连接
- 序列号
- 乱序段
- 重传段
- 部分重叠
- 序列号回绕
程序可以按两个端点建立会话,分别保存两个方向的数据。遇到重复段时跳过,遇到乱序段时进入待处理缓存。
流内容不能无限增长。可以限制每个方向最多保留 1 MB,同时设置全局内存上限。
明文文本直接显示。TLS、压缩数据和二进制内容显示十六进制预览,不要强行当作文本展示。
17. 测试和 Wireshark 对比
真实流量按以下顺序测试:
ICMP
→ ARP
→ DNS
→ TCP
→ HTTP
→ Follow Stream
保存 pcapng 后,用 Wireshark 打开同一个文件,对比:
- 源、目的 MAC
- 源、目的 IP
- 协议
- 源、目的端口
- 数据包长度
- TCP 标志位
- ICMP 类型
- 原始载荷
Wireshark 中选择:
Follow → TCP Stream → Hex Dump
就能对比同一个 TCP 流的十六进制内容。

网硕互联帮助中心





评论前必须登录!
注册