這一節是程序的核心,也是最複雜的地方html
首先須要明白的一點是,通常對於一個有界面的程序來講,每每須要多線程。本程序中除了界面線程外,抓包須要另外建立一個新的線程。在寫抓包函數以前,首先要將前面兩個模塊的結果返回到主對話框界面對應的類實現中,在SnifferDlg.cpp中,修改以前增長的兩個模塊的觸發函數以下:網絡
1 void CSnifferDlg::OnAdp() 2 { 3 // TODO: 在此添加命令處理程序代碼 4 CAdpDlg adpdlg; 5 if(adpdlg.DoModal() == IDOK) 6 { 7 m_pDevice = adpdlg.returnd(); 8 } 9 }
1 void CSnifferDlg::OnFilter() 2 { 3 // TODO: 在此添加命令處理程序代碼 4 CFilterDlg filterdlg; 5 if(filterdlg.DoModal() == IDOK) 6 { 7 int len =WideCharToMultiByte(CP_ACP,0,filterdlg.GetFilterName(),-1,NULL,0,NULL,NULL); 8 WideCharToMultiByte(CP_ACP,0,filterdlg.GetFilterName(),-1,m_filtername,len,NULL,NULL ); 9 10 } 11 }
前一個函數是在打開選擇適配器窗口後,在用戶選擇完網卡後,將選擇的網卡返回到主界面的類實現中;後一個函數是在打開設置過濾規則後,將過濾規則的字符串返回到主界面的類實現中。也許你對第二個函數中的兩個函數不太明白,這是一個寬字符轉換爲多字符的函數,就只需瞭解其中兩個參數便可,其它的複製粘貼,函數是這樣使用的。得到了前兩個模塊的返回值,就能夠來寫抓包函數了,建立一個新線程,抓包函數代碼以下:多線程
1 DWORD WINAPI CapturePacket(LPVOID lpParam) 2 { 3 CSnifferDlg *pDlg = (CSnifferDlg *)lpParam; 4 pcap_t *pCap; 5 char strErrorBuf[PCAP_ERRBUF_SIZE]; 6 int res; 7 struct pcap_pkthdr *pkt_header; 8 const u_char *pkt_data; 9 u_int netmask; 10 struct bpf_program fcode; 11 12 if((pCap=pcap_open_live(pDlg->m_pDevice->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,strErrorBuf))==NULL) 13 { 14 return -1; 15 } 16 17 if(pDlg->m_pDevice->addresses != NULL) 18 /* 得到接口第一個地址的掩碼 */ 19 netmask=((struct sockaddr_in *)(pDlg->m_pDevice->addresses->netmask))->sin_addr.S_un.S_addr; 20 else 21 /* 若是接口沒有地址,那麼咱們假設一個C類的掩碼 */ 22 netmask=0xffffff; 23 //編譯過濾器 24 if (pcap_compile(pCap, &fcode,pDlg->m_filtername, 1, netmask) <0 ) 25 { 26 AfxMessageBox(_T("請設置過濾規則")); 27 return -1; 28 } 29 //設置過濾器 30 if (pcap_setfilter(pCap, &fcode)<0) 31 return -1; 32 33 while((res = pcap_next_ex( pCap, &pkt_header, &pkt_data)) >= 0) 34 { 35 36 if(res == 0) 37 continue; 38 if(!pDlg->m_bFlag) 39 break; 40 CSnifferDlg *pDlg = (CSnifferDlg *)AfxGetApp()->GetMainWnd(); 41 pDlg->ShowPacketList(pkt_header,pkt_data); 42 pDlg = NULL; 43 } 44 45 pcap_close(pCap); 46 pDlg = NULL; 47 return 1; 48 }
解釋兩個地方,一是怎樣控制開始抓包和中止抓包,這裏採用了一個bool變量m_bFlag,這個變量初值是FALSE,當點擊菜單中的開始捕獲變量爲true,點擊中止捕獲變量又變爲false。二是當抓完一個包後,又將指針指向主界面的句柄,以後將抓來的數據包的內容在主界面中顯示。ide
主界面中有三個須要顯示抓包內容的地方,一是數據包的概略信息,用ShowPacketList函數來實現;二是數據包的詳細信息用ShowPacketTree函數來實現;三是數據包的具體內容和統計信息。這三部分是大量類似的代碼,主要涉及到對網絡協議的分析,用到的主要是判斷語句,放到下一節講吧。函數
下一節 MFC+WinPcap編寫一個嗅探器之七(協議)spa