使用Qt實(shí)現(xiàn)控制臺(tái)抓取tcp數(shù)據(jù)包
前提條件
安裝npcap: 鏈接
項(xiàng)目準(zhǔn)備
創(chuàng)建控制臺(tái)程序
在項(xiàng)目文件中添加包含目錄、附加庫(kù)目錄、附加庫(kù)
INCLUDEPATH += D:/softwares/Libs/NpcapSDK/Include LIBS += -LD:/softwares/Libs/NpcapSDK/Lib/x64 LIBS += -lwpcap LIBS += -lole32 LIBS += -lPacket LIBS += -lIphlpapi
檢查是否已經(jīng)安裝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 存不存在
獲取網(wǎng)絡(luò)適配器列表
我們需要選擇一個(gè)網(wǎng)絡(luò)適配器去抓取tcp數(shù)據(jù)包,所以需要獲取本地機(jī)器的所有網(wǎng)絡(luò)適配器,當(dāng)然 npcap 提供了 pcap_findalldevs api,但是如果我們要想獲取它的可讀化的 FriendName,需要經(jīng)過(guò)一些操作
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;
}
打開網(wǎng)絡(luò)適配器并設(shè)置篩選條件
一個(gè)網(wǎng)絡(luò)適配器抓到的tcp數(shù)據(jù)包有很多,但是我們只想關(guān)注我們想要的tcp數(shù)據(jù)包,所以需要設(shè)置篩選條件
// 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;
}
這里我們?cè)O(shè)置的條件是只篩選 端口號(hào)3000的tcp數(shù)據(jù)包,篩選字符串為: tcp port 3000
開始抓包,設(shè)置處理函數(shù)
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;
}
運(yùn)行效果

完整代碼
#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;
}
// 檢索網(wǎng)卡列表
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實(shí)現(xiàn)控制臺(tái)抓取tcp數(shù)據(jù)包的詳細(xì)內(nèi)容,更多關(guān)于Qt抓取tcp數(shù)據(jù)包的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解C++設(shè)計(jì)模式編程中對(duì)訪問者模式的運(yùn)用
這篇文章主要介紹了C++設(shè)計(jì)模式編程中對(duì)訪問者模式的運(yùn)用,訪問者模式在不破壞類的前提下為類提供增加新的新操作,需要的朋友可以參考下2016-03-03
C語(yǔ)言如何實(shí)現(xiàn)順序表(數(shù)據(jù)結(jié)構(gòu))
這篇文章主要介紹了C語(yǔ)言如何實(shí)現(xiàn)順序表(數(shù)據(jù)結(jié)構(gòu))問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
C++標(biāo)準(zhǔn)模板庫(kù)STL深入講解
STL提供了一組表示容器、迭代器、函數(shù)對(duì)象和算法的模板。容器是一個(gè)與數(shù)組類似的單元,可以存儲(chǔ)若干個(gè)值。STL容器是同質(zhì)的,即存儲(chǔ)的值的類型相同:算法是完成特定任務(wù)(如對(duì)數(shù)組進(jìn)行排序或在鏈表中查找特定值)的處方2022-12-12
C++面向?qū)ο髮?shí)現(xiàn)萬(wàn)年歷的示例代碼
本文將通過(guò)面向?qū)ο髮?shí)現(xiàn)一個(gè)簡(jiǎn)單的日歷(萬(wàn)年歷)效果,主要會(huì)有以下幾個(gè)模塊:模型、視圖、控制,感興趣的小伙伴可以動(dòng)手嘗試一下2022-06-06
淺談Qt信號(hào)槽與事件循環(huán)的關(guān)系
本文主要介紹了Qt信號(hào)槽與事件循環(huán)的關(guān)系,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08

