You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C++捕获到达指定端口的IP数据包

核心问题说明

你当前的实现逻辑和需求不匹配,普通TCP服务器根本无法读取原始以太网数据包,具体问题如下:

  • 普通IPv6 TCP套接字只能接收系统TCP/IP协议栈校验通过、且完成完整TCP握手后递交给对应端口的应用层数据,不仅拿不到以太网帧头、IP头、TCP头等原始包结构,只要回放的pcap包不符合以下任意一个条件,都会被协议栈直接丢弃,不会送到你的应用:
    • 数据包目标IP是当前监听的IPv6回环地址::1
    • 数据包是TCP协议且目标端口为42557
    • pcap中包含完整的TCP三次握手流程,能和你的TCP服务器成功建立连接
  • Wireshark能抓到包是因为它使用libpcap/Npcap这类抓包库,通过原始套接字直接从网卡驱动层面读取所有流量,绕过了系统TCP/IP协议栈的常规处理逻辑。

关于是否需要修改数据包目标IP为localhost:如果你坚持用TCP服务器的逻辑实现,就必须把pcap中数据包的目标IP改为IPv4127.0.0.1或者IPv6::1,且保证pcap包含完整TCP握手流程,否则协议栈不会处理lo接口上目标IP非本地回环地址的流量。


正确实现方案

要读取原始以太网数据包,直接用和Wireshark同底层的libpcap库实现即可,无需走TCP监听的逻辑,步骤如下:

  1. 安装对应平台的libpcap开发依赖(Linux下是libpcap-dev,Windows下用Npcap SDK),C可直接调用其C API,也可以用封装好的PcapPlusPlus等C封装库简化开发
  2. 打开lo接口,设置抓包过滤规则port 42557,即可只捕获端口为42557的所有数据包
  3. 注册回调即可直接获取完整的以太网帧原始二进制内容

参考代码片段:

#include <pcap.h>
#include <stdio.h>

// 抓包回调,每抓到一个匹配的包就会触发
void packet_cb(u_char* args, const pcap_pkthdr* pkthdr, const u_char* packet) {
    // packet指针指向的就是完整以太网帧的原始数据,按需解析即可
    printf("收到包,总长度:%d字节\n", pkthdr->len);
}

int main() {
    char errbuf[PCAP_ERRBUF_SIZE];
    // 打开lo接口,开启混杂模式,超时1000ms
    pcap_t* handle = pcap_open_live("lo", 65535, 1, 1000, errbuf);
    if (!handle) {
        printf("打开lo接口失败:%s\n", errbuf);
        return -1;
    }

    // 设置过滤规则,只抓42557端口的流量
    bpf_program filter;
    const char filter_rule[] = "port 42557";
    bpf_u_int32 net, mask;
    pcap_lookupnet("lo", &net, &mask, errbuf);
    pcap_compile(handle, &filter, filter_rule, 0, net);
    pcap_setfilter(handle, &filter);

    // 开始循环抓包
    pcap_loop(handle, 0, packet_cb, nullptr);

    pcap_close(handle);
    return 0;
}

编译指令(Linux):g++ 你的代码文件名.cpp -o packet_capture -lpcap

内容的提问来源于stack exchange,提问作者Vikash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 14:18:03