WinPcap初學(xué)(三)類(lèi)的實(shí)現(xiàn)
系統(tǒng)
1990 0
??? 距離上次發(fā)博文有兩三個(gè)星期的時(shí)候了,期間看了一些書(shū),如《Effective C++》、《Windows核心編程》。感覺(jué)對(duì)計(jì)算機(jī)有了一個(gè)新的認(rèn)識(shí),自己以前對(duì)程序的見(jiàn)解是那么膚淺,完全沒(méi)有操作系統(tǒng)的概念,也沒(méi)有程序各部分與內(nèi)存關(guān)系的認(rèn)識(shí)。下面開(kāi)始介紹這個(gè)類(lèi)。
1. 類(lèi)成員介紹?
Code
#pragma
?once
#include?
<
vector
>
#include?
"
pcap.h
"
#pragma
?comment(lib,?"wpcap.lib")
#pragma
?comment(lib,?"Packet.lib")
using
?
namespace
?std;
//
?定義回調(diào)函數(shù)指針
typedef?
void
?(
*
pcap_back)(u_char?
*
,?
const
?
struct
?pcap_pkthdr?
*
,
?????????????????
const
?u_char?
*
);
class
?CNetPacket
{
public
:
????CNetPacket(
void
);
????
~
CNetPacket(
void
);
????
//
?初始化網(wǎng)絡(luò)設(shè)備
????
int
?InitPcap(
void
);
????
//
?發(fā)送數(shù)據(jù)包
????
int
?SendPacket(
const
?UCHAR
*
,?
int
);
????
//
?返回設(shè)備列表的描述
????vector
<
CString
>
?DevMsg(
void
);
????
//
?選定用于操作的設(shè)備
????
int
?SetDev(
int
);
????????
//
?傳入回調(diào)函數(shù)地址至此函數(shù),第二個(gè)參數(shù)為接收包的個(gè)數(shù)
????
void
?GetPacket(pcap_back,?
int
);????
private
:
????
char
?m_errBuf[PCAP_ERRBUF_SIZE];
????pcap_t?
*
m_pDevHandle;
????pcap_if_t?
*
m_pAllDevs;
};
??? 這個(gè)類(lèi)包括了用于初始化網(wǎng)絡(luò)的InitPcap,用于返回網(wǎng)絡(luò)設(shè)備信息的DevMsg,用于選擇設(shè)備的SetDev,用于發(fā)送數(shù)據(jù)包的SendPacket和用于接收數(shù)據(jù)包的GetPacket。用戶(hù)必須先調(diào)用InitPcap,再調(diào)用SetDev,然后才能執(zhí)行發(fā)送或接收。由于接收函數(shù)必采用回調(diào)方式才能工作,所以這里typedef了一個(gè)回調(diào)函數(shù)的指針void packet_handler(u_char *, const struct pcap_pkthdr *, const u_char *),它的三個(gè)參數(shù)都是pcap.h里頭的回調(diào)函數(shù)的參數(shù)。實(shí)際上,從WinPcap到用戶(hù)的使用共有兩次回調(diào)的過(guò)程,一是WinPcap提供的回調(diào),另一個(gè)是封裝類(lèi)的時(shí)候提供的回調(diào)。
2. 類(lèi)的實(shí)現(xiàn)
Code
#include?
"
StdAfx.h
"
#include?
"
NetPacket.h
"
CRITICAL_SECTION?g_cs;????
//
?全局變量的關(guān)鍵段
pcap_back?m_fp;????
//
?回調(diào)函數(shù)指針的成員變量
void
?packet_handler(u_char?
*
,?
const
?
struct
?pcap_pkthdr?
*
,?
const
?u_char?
*
);????
//
?供WinPcap調(diào)用的回調(diào)函數(shù)
CNetPacket::CNetPacket(
void
)
{
????m_pDevHandle?
=
?NULL;
????m_pAllDevs?
=
?NULL;
}
CNetPacket::
~
CNetPacket(
void
)
{
????
if
(m_pDevHandle?
!=
?NULL)
????????pcap_close(m_pDevHandle);????
????DeleteCriticalSection(
&
g_cs);
}
//
?初始化網(wǎng)絡(luò)設(shè)備
int
?CNetPacket::InitPcap(
void
)
{
????InitializeCriticalSection(
&
g_cs);????
//
初始化關(guān)鍵段
????
if
(pcap_findalldevs(
&
m_pAllDevs,?m_errBuf)?
==
?
-
1
)
????????
return
?
-
1
;
????
return
?
1
;
}
//
?發(fā)送數(shù)據(jù)包,保證線(xiàn)程安全
int
?CNetPacket::SendPacket(
const
?UCHAR?
*
data,?
int
?length)
{
????EnterCriticalSection(
&
g_cs);????
//
進(jìn)入關(guān)鍵段
????
if
?(pcap_sendpacket(m_pDevHandle,????
//
?Adapter
????????data,????????????????
//
?buffer?with?the?packet
????????length????????????????????
//
?size
????????)?
!=
?
0
)
????{
????????LeaveCriticalSection(
&
g_cs);????
//
退出關(guān)鍵段,不然其他線(xiàn)程不能進(jìn)入
????????
return
?
-
1
;
????}
????LeaveCriticalSection(
&
g_cs);
????
return
?
1
;
}
//
?返回設(shè)備列表的描述
vector
<
CString
>
?CNetPacket::DevMsg(
void
)
{
????pcap_if_t?
*
d;
????vector
<
CString
>
?devMsg;
????CString?temp;
????
for
(d?
=
?m_pAllDevs;?d;?d?
=
?d
->
next)
????{
????????temp?
=
?d
->
description;
????????devMsg.push_back(temp);
????}
????
return
?devMsg;
}
//
?選定用于操作的設(shè)備
int
?CNetPacket::SetDev(
int
?devIndex)
{
????pcap_if_t?
*
d;
????
int
?i;
????
/*
?找到要選擇的網(wǎng)卡結(jié)構(gòu)?
*/
????
for
(d?
=
?m_pAllDevs,?i?
=
?
0
;?i?
<
?devIndex;?d?
=
?d
->
next,?
++
i);
????
/*
?打開(kāi)選擇的網(wǎng)卡?
*/
????
if
?(?(m_pDevHandle?
=
?pcap_open_live(d
->
name,?
//
?設(shè)備名稱(chēng)
??????????????????
65536
,???
//
?portion?of?the?packet?to?capture.?
??????????????????
//
?65536?grants?that?the?whole?packet?will?be?captured?on?all?the?MACs.
??????????????????
1
,???????
//
?混雜模式
??????????????????
1000
,?????
//
?讀超時(shí)為1秒
??????????????????m_errBuf???
//
?error?buffer
??????????????????)?)?
==
?NULL)
????{
????????
/*
?釋放網(wǎng)絡(luò)設(shè)備?
*/
????????pcap_freealldevs(m_pAllDevs);
????????
return
?
-
1
;
????}
????
/*
釋放網(wǎng)絡(luò)設(shè)備
*/
????pcap_freealldevs(m_pAllDevs);
????
return
?
1
;
}
//
?傳入回調(diào)函數(shù)地址至此函數(shù)
void
?CNetPacket::GetPacket(pcap_back?fp,?
int
?cnt)
{
????m_fp?
=
?fp;
????
/*
?開(kāi)始捕獲包?
*/
????pcap_loop(m_pDevHandle,?cnt,?packet_handler,?NULL);
}
/*
?對(duì)每一個(gè)到來(lái)的數(shù)據(jù)包調(diào)用該函數(shù)?
*/
void
?packet_handler(u_char?
*
param,?
const
?
struct
?pcap_pkthdr?
*
header,?
const
?u_char?
*
pkt_data)
{
????m_fp(param,?header,?pkt_data);
}
??? SendPacket中使用了關(guān)鍵段保證線(xiàn)程安全,這樣子在使用多線(xiàn)程的時(shí)候就不會(huì)因?yàn)榫W(wǎng)絡(luò)設(shè)備被同時(shí)調(diào)用而出錯(cuò)。SendPacket的參數(shù)包括了一個(gè)UCHAR指針及待發(fā)送數(shù)據(jù)的長(zhǎng)度,用戶(hù)使用時(shí)把待發(fā)送的數(shù)組的地址傳入?yún)?shù)一,把數(shù)組長(zhǎng)度傳入?yún)?shù)二。GetPacket的參數(shù)包括一個(gè)函數(shù)指針及接收數(shù)據(jù)包的數(shù)目,這里的函數(shù)指針就是用戶(hù)需要被回調(diào)的函數(shù)的地址。用戶(hù)使用的時(shí)候把函數(shù)名(即函數(shù)指針)傳入?yún)?shù)一,把接收的數(shù)據(jù)包的個(gè)數(shù)傳入?yún)?shù)二,當(dāng)有數(shù)據(jù)包被檢測(cè)到的時(shí)候回調(diào)函數(shù)就會(huì)被執(zhí)行,當(dāng)接收的數(shù)據(jù)包的數(shù)目超出cnt時(shí),pcap_loop就會(huì)退出(在此之前pcap_loop是沒(méi)有退出的,它是一個(gè)循環(huán)并阻塞等待數(shù)據(jù)包的函數(shù))。
??? 由于本人是從C#轉(zhuǎn)過(guò)來(lái)的(雖然開(kāi)始學(xué)的是C++,后來(lái)由于種種原因開(kāi)始使用起C#),對(duì)于event方式的回調(diào)比較熟悉。開(kāi)始要寫(xiě)C++的回調(diào)一直沒(méi)弄明白,查了一些中文的資料覺(jué)得都看得糊里糊涂的,后來(lái)看到外國(guó)的資料才明白了
http://www.newty.de/fpt/callback.html
。其實(shí)回調(diào)的關(guān)鍵就是把需要被回調(diào)的函數(shù)的地址作為參數(shù)傳入另一個(gè)函數(shù),還有你必須給這個(gè)函數(shù)定義一個(gè)格式,如參數(shù)和返回值,這樣子回調(diào)的時(shí)候程序才能根據(jù)地址及參數(shù)列表從內(nèi)存中調(diào)用被回調(diào)的函數(shù)。當(dāng)然,定義函數(shù)格式的話(huà)可以通過(guò)typedef的形式在頭文件中定義,也可以在參數(shù)列表中直接定義,如void (*p) (...)這樣。
3.寫(xiě)在后面
??? 發(fā)送函數(shù)只調(diào)用了比較簡(jiǎn)單的pcap_sendpacket,而接收也是調(diào)用了pcap_loop??赡苣阋舶l(fā)現(xiàn)了發(fā)送還有pcap_sendqueue_queue,接收還有pcap_next_ex,不過(guò)對(duì)于簡(jiǎn)單的任務(wù)使用前者就足夠了。
WinPcap初學(xué)(三)類(lèi)的實(shí)現(xiàn)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元