??統計引擎利用了內核級的數據包過濾器,來有效地為收集到的數據包進行分類。為了使用這個特性,編程人員必須打開一個適配器,并且,可以使用pcap_setmode()將它設置為統計模式(statistical mode)。 特別注意,必須使用MODE_STAT來作為這個函數的mode參數。
??在統計模式下,編寫一個用于監聽TCP網絡流量的程序并不復雜,代碼也不多。
??實現源碼:
[cpp] view plain copy print ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? #include?<pcap.h> ??#include?<remote-ext.h> ??#pragma?comment(lib,"Packet.lib")??? ??#pragma?comment(lib,"wpcap.lib") ??#pragma?comment(lib,"ws2_32.lib") ??void ?usage();??void ?dispatcher_handler(?u_char?*,?const ?struct ?pcap_pkthdr?*,?const ?u_char?*?);??void ?main(?int ?argc,?char ?**argv)????{?? ????pcap_t?*fp;?? ????char ?error[PCAP_ERRBUF_SIZE];?? ????struct ?timeval?st_ts;?? ????u_int?netmask;?? ????struct ?bpf_program?fcode;?? ?????? ????if ?(?argc?!=?2?)?? ????{?? ????????usage();?? ????????return ;?? ????}?? ?????? ????if ?(?(?fp?=?pcap_open_live(?argv[1],?100,?1,?1000,?error?)?)?==?NULL?)?? ????{?? ????????fprintf_s(?stderr,?"/n適配器打開失敗:?%s/n" ,?error?);?? ????????return ;?? ????}?? ?????? ????netmask=0xffffff;?? ?????? ????if ?(?pcap_compile(?fp,?&fcode,?"tcp" ,?1,?netmask?)?<?0?)?? ????{?? ????????fprintf_s(?stderr,"/n不能編譯包過濾器,檢查語法./n" ?);?? ?????????? ????????return ;?? ????}?? ???? ?? ????if ?(?pcap_setfilter(?fp,?&fcode?)?<?0?)?? ????{?? ????????fprintf_s(?stderr,?"/n過濾器設置失敗./n" ?);?? ?????????? ????????return ;?? ????}?? ?????? ????pcap_setmode(?fp,?MODE_STAT?);?? ????printf_s(?"TCP?流量統計:/n" ?);?? ?????? ????pcap_loop(?fp,?0,?dispatcher_handler,?(PUCHAR )&st_ts?);?? ????pcap_close(fp);?? ????return ;?? }?? void ?dispatcher_handler(?u_char?*state,?const ?struct ?pcap_pkthdr?*header,?const ?u_char?*pkt_data?)??{?? ????struct ?timeval?*old_ts?=?(struct ?timeval?*)state;?? ????u_int?delay;?? ????LARGE_INTEGER?Bps,Pps;?? ????struct ?tm ?ltime;?? ????char ?timestr[16];?? ?????? ?????? ????delay?=(header->ts.tv_sec?-?old_ts->tv_sec)?*?1000000?-?old_ts->tv_usec?+?header->ts.tv_usec;?? ?????? ????Bps.QuadPart?=?(((*(LONGLONG *)(pkt_data?+?8))?*?8?*?1000000)?/?(delay));?? ????? ? ? ? ? ? ? ?? ?????? ????Pps.QuadPart?=?(((*(LONGLONG *)(pkt_data))?*?1000000)?/?(delay));?? ?????? ????time_t ?t?=?(time_t ?)&header->ts.tv_sec;?? ????localtime_s(?<ime,?&t?);?? ????strftime(?timestr,?sizeof ?timestr,?"%H:%M:%S" ,?<ime);?? ????printf_s("%s,/t%.6d毫秒/t長度:%d/n" ,?timestr,?header->ts.tv_usec,?header->len?);?? ?????? ????printf_s("%s?" ,?timestr);?? ?????? ????printf_s(?"BPS=%I64u??" ,?Bps.QuadPart?);?? ????printf_s(?"PPS=%I64u/n" ,?Pps.QuadPart?);?? ?????? ????old_ts->tv_sec=header->ts.tv_sec;?? ????old_ts->tv_usec=header->ts.tv_usec;?? }?? void ?usage()??{?? ????printf_s("/nUsage:/n" );?? ????printf_s("/t?tcptop?adapter/n" );?? ????printf_s("/t?You?can?use?/" WinDump?-D/"?if?you?don‘t?know?the?name?of?your?adapters./n" );?? ????exit(0);?? }??
/
// Name: TrafficCount.cpp
// Purpose: wincap收集并統計網絡流量。
// Compiler: VS2005
// Author: 陳相禮
// Modified by:
// Created: 09/18/09
// Copyright:
// Licence:
/
#include <pcap.h>
#include <remote-ext.h>
#pragma comment(lib,"Packet.lib")
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"ws2_32.lib")
void usage();
void dispatcher_handler( u_char *, const struct pcap_pkthdr *, const u_char * );
void main( int argc, char **argv)
{pcap_t *fp;char error[PCAP_ERRBUF_SIZE];struct timeval st_ts;u_int netmask;struct bpf_program fcode;/* 檢查命令行參數的合法性 */if ( argc != 2 ){usage();return;}/* 打開輸出適配器 */if ( ( fp = pcap_open_live( argv[1], 100, 1, 1000, error ) ) == NULL ){fprintf_s( stderr, "/n適配器打開失敗: %s/n", error );return;}/* 不用關心掩碼,在這個過濾器中,它不會被使用 */netmask=0xffffff;// 編譯過濾器if ( pcap_compile( fp, &fcode, "tcp", 1, netmask ) < 0 ){fprintf_s( stderr,"/n不能編譯包過濾器,檢查語法./n" );/* 釋放設備列表 */return;}// 設置過濾器if ( pcap_setfilter( fp, &fcode ) < 0 ){fprintf_s( stderr, "/n過濾器設置失敗./n" );/* 釋放設備列表 */return;}/* 將網卡設置為統計模式 */pcap_setmode( fp, MODE_STAT );printf_s( "TCP 流量統計:/n" );/* 開始主循環 */pcap_loop( fp, 0, dispatcher_handler, (PUCHAR)&st_ts );pcap_close(fp);return;
}
void dispatcher_handler( u_char *state, const struct pcap_pkthdr *header, const u_char *pkt_data )
{struct timeval *old_ts = (struct timeval *)state;u_int delay;LARGE_INTEGER Bps,Pps;struct tm ltime;char timestr[16];/* 以微妙計算上一次采樣的延遲時間 *//* 這個值通過采樣到的時間戳獲得 */delay =(header->ts.tv_sec - old_ts->tv_sec) * 1000000 - old_ts->tv_usec + header->ts.tv_usec;/* 獲得每秒的比特數 */Bps.QuadPart = (((*(LONGLONG*)(pkt_data + 8)) * 8 * 1000000) / (delay));/* ^ ^| || | | |將字節轉換成比特 -- ||延時是以微妙表示的 --*//* 獲得每秒的數據包數 */Pps.QuadPart = (((*(LONGLONG*)(pkt_data)) * 1000000) / (delay));/* 將時間戳轉變為易讀的標準格式*/time_t t = (time_t )&header->ts.tv_sec;localtime_s( <ime, &t );strftime( timestr, sizeof timestr, "%H:%M:%S", <ime);printf_s("%s,/t%.6d毫秒/t長度:%d/n", timestr, header->ts.tv_usec, header->len );/* 打印時間戳*/printf_s("%s ", timestr);/* 打印采樣結果 */printf_s( "BPS=%I64u ", Bps.QuadPart );printf_s( "PPS=%I64u/n", Pps.QuadPart );//存儲當前的時間戳old_ts->tv_sec=header->ts.tv_sec;old_ts->tv_usec=header->ts.tv_usec;
}
void usage()
{printf_s("/nUsage:/n");printf_s("/t tcptop adapter/n");printf_s("/t You can use /"WinDump -D/" if you don‘t know the name of your adapters./n");exit(0);
}
?
??在設置為統計模式前可以設置一個過濾器來指定要捕獲的協議包。如果沒有設置過濾器那么整個網絡數據都將被監視。一旦設置了過濾器就可以調用pcap_setmode()來設置為統計模式,之后網卡開始工作在統計模式下。
??需要指出的是pcap_open_live()的第四個參數(to_ms)定義了采樣的間隔,回調函數pcap_loop()每隔一定間隔就獲取一次采樣統計,這個采樣被裝入pcap_loop()的第二和第三個參數,過程如下圖所示:
____________________
|struct timeval ts |?
|__________________|
|bpf_u_int32? ??? ? |
|caplen=16 ? ? ? ? | struct pcap_pkthdr*
|__________________| (參數2)
| bpf_u_int32 ? ? ?|
| len=16 ? ? ? ? ? |
|__________________|
________________________________
|large_integer Accepted packet |
|______________________________| uchar *
| large_integer Accepted bits ?| (參數3)
|______________________________|
??用兩個64位的計數器分別記錄最近一次間隔數據包數量和比特數量。
??本例子中,網卡打開時設置超時為1000毫秒,也就是說dispatcher_handler()每隔1秒就被調用一次。過濾器也設置為只監視TCP包,然后pcap_setmode() and pcap_loop()被調用,注意一個指向timeval的指針作為參數傳送到pcap_loop()。這個timeval結構將用來存儲個時間戳以計算兩次采樣的時間間隔。
??dispatcher_handler()用該間隔來獲取每秒的比特數和數據包數,并把著兩個數顯示在顯示器上。
最后指出的是目前這個例子是比任何一個利用傳統方法在用戶層統計的包捕獲程序都高效。因為統計模式需要最小數量的數據拷貝和上下環境交換,同時還有最小的內存需求,所以CPU是最優的。
?
?
此文章來自于【
http://blog.csdn.net/eaglewood2005/article/details/4567727
】
總結
以上是生活随笔 為你收集整理的【笔记】wincap收集并统计网络流量 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。