必须用 libpcap 从数据链路层抓包并手动重组 TCP 流以获取完整 HTTP 请求/响应,因 HTTPS 加密无法解密、非标端口需扩展过滤、高层协议关键字不可靠、单包解析易失败,且需处理混杂模式权限、乱序重传及缓冲区调优。

用 libpcap 抓原始网卡包,不是用 socket 监听 HTTP 端口
想拿到“所有流入的 HTTP 数据包”,不能靠 bind(80) 或 listen()——那只能捕获发给本机且应用层真在监听 80/443 的连接。真实场景里,HTTP 流量可能目标是局域网其他设备、被 NAT 转发、或只是经过本机(混杂模式下可看到)。必须从数据链路层抓包,再自己解析 TCP + HTTP。
核心工具是 libpcap(Linux/macOS)或 WinPcap/Npcap(Windows),C++ 调用其 C 接口即可。别试图用 std::net 或 Boost.Beast——它们不提供链路层访问能力。
过滤器写成 "tcp port 80 or tcp port 443",但注意 HTTPS 是加密的
用 pcap_compile() + pcap_setfilter() 加 BPF 过滤器能大幅降低 CPU 和内核拷贝开销。直接抓全量包再 in-app 过滤 TCP 端口,效率低且容易丢包。
-
"tcp port 80"可捕获明文 HTTP 请求/响应,但注意:有些客户端用非标端口(如 8080、8888),需按需扩展 -
"tcp port 443"只能拿到 TLS 握手和加密载荷,无法解出 URL、Header、Body——没有私钥,就不可能解密 TLS;SNI 域名可从 ClientHello 里提取,但得手动解析 TLS 记录头 - 避免写
"port 80"(含 UDP),HTTP 几乎不用 UDP;也不要用"http"——libpcap 的高层协议关键字(如 http、ftp)不可靠,且只匹配部分载荷,易漏包
解析 HTTP 需自己处理 TCP 流重组,不能直接对每个 packet 调 strstr()
一个 HTTP 请求或响应往往跨多个 TCP segment,尤其大响应体或启用了 TCP segmentation offload(TSO)的网卡。libpcap 给你的只是单个 IP 包(可能含半个 HTTP 头+半截 Body),strstr(buffer, "HTTP/1.1") 很可能永远找不到。
立即学习“C++免费学习笔记(深入)”;
- 必须维护 per-flow(src_ip+src_port+dst_ip+dst_port)的 TCP 有序字节流缓冲区
- 要处理 TCP 标志位:
SYN初始化序列号,FIN/RST清理缓冲区,PSH提示上层可交付 - 简单方案:用
libtins(C++ 封装库)自带的TCPStreamFollower;纯 libpcap 则需手撸滑动窗口逻辑 - 注意乱序包、重传包、IPv6 分片——生产环境必须考虑,测试时关掉 TSO/GSO(
ethtool -K eth0 tso off gso off)可简化调试
权限、混杂模式与性能取舍必须手动控制
普通用户无法打开网卡混杂模式,pcap_open_live() 会失败并报错 "permissin denied"。Linux 下要么加 cap_net_raw,要么用 sudo;macOS 需开启「完全磁盘访问」+「网络监控」权限;Windows 依赖 Npcap 安装时选「以管理员身份安装驱动」。
- 混杂模式(
PROMISCUOUS)决定能否看到非发给本机 MAC 的包——局域网嗅探必需,但虚拟机桥接/容器环境下行为复杂,先tcpdump -i eth0 -c 1验证是否真能抓到其他设备流量 -
timeout_ms设太小(如 1)会导致频繁唤醒线程,CPU 升高;设太大(如 1000)则实时性差;建议 10–50ms 平衡 - 抓包缓冲区大小(
BUFSIZ参数)默认常为 2MB,突发流量大时会丢包,可用pcap_set_buffer_size()提前设为 16MB
HTTP 是应用层协议,而网卡看到的是以太网帧。跳过 TCP 流重组直接解析 payload,90% 的 case 会得到乱码或截断内容。真正稳定获取完整 HTTP 交互,关键不在“怎么抓”,而在“怎么把零散 TCP 片段拼回语义完整的请求/响应”。


















