使用Qt实现控制台抓取tcp数据包

 更新时间:2025年11月11日 08:19:57   作者:user5033926650859  
这篇文章主要为大家详细介绍了如何使用Qt实现控制台抓取tcp数据包,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前提条件

安装npcap: 链接

项目准备

创建控制台程序

在项目文件中添加包含目录、附加库目录、附加库

INCLUDEPATH += D:/softwares/Libs/NpcapSDK/Include
LIBS += -LD:/softwares/Libs/NpcapSDK/Lib/x64
LIBS += -lwpcap
LIBS += -lole32
LIBS += -lPacket
LIBS += -lIphlpapi

检查是否已经安装npcap

bool checkNpcapExist()
{
    WCHAR path[512];
    uint len = GetSystemDirectory(path, 480);
    QString systemPath = QString::fromWCharArray(path, len);

    QString npcapFolder = QDir(systemPath).filePath("Npcap");
    return QDir(npcapFolder).exists();
}

也就是判断目录: C:\Windows\System32\Npcap 存不存在

获取网络适配器列表

我们需要选择一个网络适配器去抓取tcp数据包,所以需要获取本地机器的所有网络适配器,当然 npcap 提供了 pcap_findalldevs api,但是如果我们要想获取它的可读化的 FriendName,需要经过一些操作

QString getDeviceFriendName(const char *devName)
{
    QString friendName(devName);

    // extract guid string by regex
    QRegularExpression regex(R"(({[A-F0-9\-]+}))");
    auto match = regex.match(friendName);

    if (!match.hasMatch()) return friendName;

    // translate guid string to GUID
    GUID guid;

    HRESULT hr = CLSIDFromString(match.captured(1).toStdWString().c_str(), &guid);

    if (!SUCCEEDED(hr)) return friendName;

    // GUID => LUID => Alias(FriendName)
    NET_LUID luid;
    if (0 == ConvertInterfaceGuidToLuid(&guid, &luid))
    {
        WCHAR buffer[256] = {0};
        if (0 == ConvertInterfaceLuidToAlias(&luid, buffer, 256))
        {
            friendName = QString::fromWCharArray(buffer);
        }
    }

    return friendName;
}

int main()
{
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t *alldevs;
    // pcap_t *handle;

    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
        qCritical() << "Error in pcap_findalldevs:" << errbuf;
        return -1;
    }

    QStringList devNames;
    pcap_if_t *dev = alldevs;
    char* lastName = nullptr;
    while (dev)
    {
        QString devName = getDeviceFriendName(dev->name);
        devNames.append(devName);
        lastName = dev->name;
        dev = dev->next;
    }
    return 0;
}

打开网络适配器并设置筛选条件

一个网络适配器抓到的tcp数据包有很多,但是我们只想关注我们想要的tcp数据包,所以需要设置筛选条件

// open the adapter
pcap_t* adapter = pcap_open_live(lastName, 65536, 1, 1000, errbuf);
if (adapter == nullptr)
{
    pcap_freealldevs(alldevs);
    qDebug() << "fail to open the net adapter: " << lastName;
    return -1;
}

pcap_freealldevs(alldevs);

// set filter
struct bpf_program fcode;
int res = 0;
if ((res = pcap_compile(adapter, &fcode, "tcp port 3000", 1, PCAP_NETMASK_UNKNOWN)) < 0)
{
    qDebug() << "fail to compile:" << pcap_statustostr(res);
    pcap_close(adapter);
    return -1;
}
if ((res = pcap_setfilter(adapter, &fcode) < 0))
{
    qDebug() << "fail to set filter:" << pcap_statustostr(res);
    pcap_close(adapter);
    return -1;
}

这里我们设置的条件是只筛选 端口号3000的tcp数据包,筛选字符串为: tcp port 3000

开始抓包,设置处理函数

void main()
{
    // start capture loop
    pcap_loop(adapter, 0, packet_handler, nullptr);

    pcap_close(adapter);
}

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
    Q_UNUSED(param);
    Q_UNUSED(pkt_data);

    uint len = header->len;
    QString str = QString::asprintf("%ld:%ld (%ld)", header->ts.tv_sec, header->ts.tv_usec, len);
    qDebug() << str;
}

运行效果

完整代码

#include <QCoreApplication>
#include <winsock2.h>
#include <QDebug>
#include <windows.h>
#include <QDir>
#include <pcap.h>
#include <QRegularExpression>
#include <objbase.h>
#include <netioapi.h>

bool checkNpcapExist()
{
    WCHAR path[512];
    uint len = GetSystemDirectory(path, 480);
    QString systemPath = QString::fromWCharArray(path, len);

    QString npcapFolder = QDir(systemPath).filePath("Npcap");
    return QDir(npcapFolder).exists();
}

QString getDeviceFriendName(const char *devName)
{
    QString friendName(devName);

    // extract guid string by regex
    QRegularExpression regex(R"(({[A-F0-9\-]+}))");
    auto match = regex.match(friendName);

    if (!match.hasMatch()) return friendName;

    // translate guid string to GUID
    GUID guid;

    HRESULT hr = CLSIDFromString(match.captured(1).toStdWString().c_str(), &guid);

    if (!SUCCEEDED(hr)) return friendName;

    // GUID => LUID => Alias(FriendName)
    NET_LUID luid;
    if (0 == ConvertInterfaceGuidToLuid(&guid, &luid))
    {
        WCHAR buffer[256] = {0};
        if (0 == ConvertInterfaceLuidToAlias(&luid, buffer, 256))
        {
            friendName = QString::fromWCharArray(buffer);
        }
    }

    return friendName;
}

void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
    Q_UNUSED(param);
    Q_UNUSED(pkt_data);

    // struct tm* ltime;
    // char timestr[16];
    // time_t local_tv_sec;

    uint len = header->len;
    QString str = QString::asprintf("%ld:%ld (%ld)", header->ts.tv_sec, header->ts.tv_usec, len);
    qDebug() << str;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 判断npcap是否存在
    if (!checkNpcapExist())
    {
        qDebug() << "Npcap not exists";
        return -1;
    }

    // 检索网卡列表
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t *alldevs;
    // pcap_t *handle;

    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
        qCritical() << "Error in pcap_findalldevs:" << errbuf;
        return -1;
    }

    QStringList devNames;
    pcap_if_t *dev = alldevs;
    char* lastName = nullptr;
    while (dev)
    {
        QString devName = getDeviceFriendName(dev->name);
        devNames.append(devName);
        lastName = dev->name;
        dev = dev->next;
    }

    // open the adapter
    pcap_t* adapter = pcap_open_live(lastName, 65536, 1, 1000, errbuf);
    if (adapter == nullptr)
    {
        pcap_freealldevs(alldevs);
        qDebug() << "fail to open the net adapter: " << lastName;
        return -1;
    }

    pcap_freealldevs(alldevs);

    // set filter
    struct bpf_program fcode;
    int res = 0;
    if ((res = pcap_compile(adapter, &fcode, "tcp port 3000", 1, PCAP_NETMASK_UNKNOWN)) < 0)
    {
        qDebug() << "fail to compile:" << pcap_statustostr(res);
        pcap_close(adapter);
        return -1;
    }
    if ((res = pcap_setfilter(adapter, &fcode) < 0))
    {
        qDebug() << "fail to set filter:" << pcap_statustostr(res);
        pcap_close(adapter);
        return -1;
    }

    // start capture loop
    pcap_loop(adapter, 0, packet_handler, nullptr);

    pcap_close(adapter);

    qDebug() << "hello";

    return a.exec();
}

以上就是使用Qt实现控制台抓取tcp数据包的详细内容,更多关于Qt抓取tcp数据包的资料请关注脚本之家其它相关文章!

相关文章

  • C++ 排序插入排序实例详解

    C++ 排序插入排序实例详解

    这篇文章主要介绍了C++ 排序插入排序实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • C++实现LeetCode(125.验证回文字符串)

    C++实现LeetCode(125.验证回文字符串)

    这篇文章主要介绍了C++实现LeetCode(验证回文字符串).本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言中回调函数和qsort函数的用法详解

    C语言中回调函数和qsort函数的用法详解

    这篇文章主要为大家详细介绍一下C语言中回调函数和qsort函数的用法教程,文中的示例代码讲解详细,对我们学习C语言有一定帮助,需要的可以参考一下
    2022-07-07
  • C++中的explicit关键字详解

    C++中的explicit关键字详解

    这篇文章主要介绍了C++中的explicit关键字详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • 使用VS2019编译CEF2623项目的libcef_dll_wrapper.lib的方法

    使用VS2019编译CEF2623项目的libcef_dll_wrapper.lib的方法

    这篇文章主要介绍了使用VS2019编译CEF2623项目的libcef_dll_wrapper.lib的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • C++之openFrameworks框架介绍

    C++之openFrameworks框架介绍

    本章我们将介绍一个非常好用的跨平台的 C++开源框架 openFrameworks。它是一个开源的跨平台的C++工具包,方便开发者创建出一个更简单和直观的框架,擅长开发图像和动画,感兴趣的同学可以参考一下
    2023-05-05
  • c++实现单纯形法现行规划问题的求解(推荐)

    c++实现单纯形法现行规划问题的求解(推荐)

    这篇文章主要介绍了c++实现单纯形法现行规划问题的求解,本文针对问题通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • C语言三子棋小游戏的实现

    C语言三子棋小游戏的实现

    这篇文章主要为大家详细介绍了C语言三子棋小游戏的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C语言目标文件的详细讲解

    C语言目标文件的详细讲解

    最近正在阅读关于C语言的库,但是我还没有find关于目标文件的解释,这篇文章主要给大家介绍了C语言目标文件的详细讲解,文中介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • C++中多才多艺的 const

    C++中多才多艺的 const

    在C++中,关键字const可以用来修饰任何作用域内的变量、函数参数、函数本体、函数返回值、成员函数、迭代器,也可以用来修饰指针本身和指针目标,可谓多才多艺,我们要详细了解其内部细节,以及逻辑奥秘,让这把多功能瑞士军刀尽情发挥其作用,需要的朋友可以参考一下
    2021-09-09

最新评论