监控IP包流量05062124吴文强文档格式.docx
《监控IP包流量05062124吴文强文档格式.docx》由会员分享,可在线阅读,更多相关《监控IP包流量05062124吴文强文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
),一个清空列表按钮,最后一个是列表控制框(用于显示最后捕获的数据统计),此时的界面如下图:
图2初始化界面
(2)向工程里添加C++头文件,命名为IPNodeList(存储结构接点和链表的定义),代码如下:
//IP结点类,存放IP包的源IP地址和其它发送数据包个数
classIPNode
{private:
longm_lIPAddress;
//IP地址
longm_lCount;
//发送数据包数
public:
IPNode*pNext;
//构造函数
IPNode(longsourceIP)
{m_lIPAddress=sourceIP;
m_lCount=1;
//初始化数据包个数为1
}
voidaddCount()
{m_lCount++;
//返回数据包个数
longgetCount()
{returnm_lCount;
//返回IP地址
longgetIPAddress()
{returnm_lIPAddress;
};
//结点链表
classNodeList
{IPNode*pHead;
//链表头
IPNode*pTail;
//链表尾
NodeList()
{pHead=pTail=NULL;
~NodeList()
{if(pHead!
=NULL)
{IPNode*pTemp=pHead;
pHead=pHead->
pNext;
deletepTemp;
//将IP结点加入链表
voidaddNode(longsourceIP)
{if(pHead==NULL)//当链表为空时
{pTail=newIPNode(sourceIP);
pHead=pTail;
pTail->
pNext=NULL;
else//当链表不为空时
{for(IPNode*pTemp=pHead;
pTemp;
pTemp=pTemp->
pNext)
{//如果链表中存在此IP,发送数据包个数加1
if(pTemp->
getIPAddress()==sourceIP)
{pTemp->
addCount();
break;
//如果链表中没有此IP,则加入链表
if(pTemp==NULL)
{pTail->
pNext=newIPNode(sourceIP);
pTail=pTail->
}
IPNode*GetpHead()
{returnpHead;
(3)本次设计需要用到Winpcap软件,必须设置VC的环境,首先下载wpdpack,解压后看到其中包含docs,Includes,lib,Examples等文件,然后打开VC,点击“Tools->
Option->
Directories”,在includefiles添加……\wpdpack\Include目录;
在Libraryfiles中添加……\wpdpack\Lib目录
(4)在IPStatisticDlg.cpp中添加下列头文件:
#include"
stdafx.h"
#include"
IPStatistic.h"
IPStatisticDlg.h"
IPNodeList.h"
#include<
iostream.h>
iomanip.h>
fstream.h>
stdlib.h>
stdio.h>
conio.h>
pcap.h"
#pragmacomment(lib,"
Wpcap.lib"
)
Ws2_32.lib"
(5)定义一些程序中将要用的全局变量和IP包的头部结构,如下:
//IP包的头部结构
structip_header{
unsignedcharver_ihl;
unsignedchartos;
unsignedshorttlen;
unsignedshortidentification;
unsignedshortflags_fo;
unsignedcharttl;
unsignedcharproto;
unsignedshortcrc;
DWORDsaddr;
DWORDdaddr;
unsignedintop_pad;
};
pcap_if_t*d;
//当前所用网卡
pcap_if_t*alldev[5];
//所有网卡存储数组
pcap_t*fp;
//网卡描述符
charerrbuf[PCAP_ERRBUF_SIZE];
//错误信息存储
unsignedintnetmask;
//子网掩码
charpacket_filter[]="
ip"
;
//过滤,选择IP协议
structbpf_programfcode;
//将过滤规则转换为内核能够处理的字节码
structpcap_pkthdr*header;
constunsignedchar*pkt_data;
NodeListlink;
//存储数据用链表
boolcapstop;
//信号量:
线程需要中止。
CWinThread*cap;
//定义线程
intcount=0;
//计数器
(6)窗口初始化时加入的一些关键代码如下:
pcap_if_t*alldevs;
//网卡链表的一个指针
if(pcap_findalldevs(&
alldevs,errbuf)==-1)
MessageBox("
找不到网卡!
"
);
//查找网卡
inti;
for(d=alldevs,i=0;
d;
d=d->
next,i++)
{m_comboboxx.AddString(d->
description);
//下拉列表中显示网卡描述
alldev[i]=d;
}
//将网卡存入数组中
m_comboboxx.SetCurSel(0);
//下拉列表中第一项显示0号网卡
m_listcontrol.InsertColumn(0,"
SourceIP"
LVCFMT_LEFT,170,-1);
//列表控制框标题栏
m_listcontrol.InsertColumn(1,"
Packetnumbers"
LVCFMT_LEFT,155,-1);
GetDlgItem(IDC_BUTTON3)->
EnableWindow(false);
//初始停止按钮不可用
此时已经找到主机上的网卡并加入到下拉列表中供用户选择,此时的界面如下:
图3初始化窗口(有网卡选择)
(7)捕获包线程函数定义如下:
UINTThreadcap()
{
if((fp=pcap_open_live(d->
name,65536,1,1000,errbuf))==NULL)//以混杂模式打开网卡
{AfxMessageBox("
无法打开指定网卡!
"
return0;
}
if(d->
addresses!
netmask=((structsockaddr_in*)(d->
addresses->
netmask))->
sin_addr.S_un.S_addr;
//获得子网掩码
else
netmask=0xffffff;
if(pcap_compile(fp,&
fcode,packet_filter,1,netmask)<
0)//编辑过滤器
{AfxMessageBox("
\n无法编辑过器!
\n"
return0;
if(pcap_setfilter(fp,&
fcode)<
0)//设置过滤器
{AfxMessageBox("
\n设置过滤器失败!
return0;
}
CIPStatisticDlg*pall=(CIPStatisticDlg*)(CWnd:
:
FromHandle(AfxGetMainWnd()->
m_hWnd));
intres;
while((res=pcap_next_ex(fp,&
header,&
pkt_data))>
=0)//循环抓包
{if(res==0)//如果没抓到包,则结束此次循环
continue;
if(capstop==false){break;
}//接收到停止按钮发来的终止线程信号,终止线程
count++;
//如果抓到包,计数器加1
CStrings;
s.Format("
%d\n"
count);
pall->
GetDlgItem(IDC_CLOCK)->
SetWindowText(s);
//改变显示所抓到的包个数
ip_header*ih;
//一个临时存储
ih=(ip_header*)(pkt_data+14);
//找到IP头的位置
link.addNode(ih->
saddr);
//将源IP地址加入链表
return1;
(8)捕获按钮关键代码:
voidCIPStatisticDlg:
OnButton1()
d=alldev[m_comboboxx.GetCurSel()];
//找到用户选择的网卡
GetDlgItem(IDC_STATE)->
SetWindowText("
正在捕获中..."
//显示当前状态
GetDlgItem(IDC_COMBO1)->
//网卡列表不可用
GetDlgItem(IDC_BUTTON1)->
//开始捕获按钮不可用
EnableWindow(true);
//停止按钮变为可用
m_listcontrol.DeleteAllItems();
capstop=true;
//信号量赋值
cap=AfxBeginThread((AFX_THREADPROC)Threadcap,NULL);
//创建线程并立即执行
(9)停止按钮代码:
OnButton3()
{GetDlgItem(IDC_STATE)->
已停止捕获!
//显示当前状态
//网卡列表可用
//开始捕获按钮可用
//停止按钮不可用
capstop=false;
//发送信号,终止线程
ofstreamfout("
login.txt"
ios:
app);
//日志记录文件
fout<
<
\t捕获IP包记录如下:
endl;
//往日志文件写东西
fout<
开始时间为:
time_ttmp=time(NULL);
ctime(&
tmp);
//写入当前系统时间作为捕获开始时间
SourIP"
\tpacketnumbers"
chartmpstr[50];
//临时存储输出字符用的字符数组
for(IPNode*pTemp=link.GetpHead();
pNext)//输出结果到日志与列表
{longlTemp=pTemp->
getIPAddress();
longr=pTemp->
getCount();
inet_ntoa(*(in_addr*)&
(lTemp))<
'
\t'
pTemp->
getCount()<
introw=m_listcontrol.InsertItem(0,inet_ntoa(*(in_addr*)&
(lTemp)));
//将存储的源地址输出到列表控制框中
sprintf(tmpstr,"
%ld"
(long*)r);
//将r转换为字符型
m_listcontrol.SetItemText(row,1,tmpstr);
}//将存储的源IP地址所对应的包个数输出到列表控制框中
(10)退出按钮代码:
OnButton2()//退出按钮
{PostQuitMessage(0);
(11)清空按钮代码:
voidCIPStatisticDlg:
OnButton4()
{
//清空列表控制框
五.系统调试与测试
(一)程序的运行
(1)由图3中的有网卡选择的初始化界面继而完善各个按钮功能以及抓包线程的定义后,程序可以运行,运行界面如下:
图4捕获包中
(2)再以上界面的基础上按下停止按钮后,进入停止状态。
此时截图如下:
图5停止捕获
(3)停止捕获后在界面上已经显示了IP数据包的统计结果,同时我门有日志文件进行存储,日志文件中记录的文件情况如下:
捕获IP包记录如下:
SunJun2919:
00:
392008
SourIPpacketnumbers
58.61.32.2523
117.40.11.1795
220.181.37.554
(二)程序设计实现与调试中遇到的问题以及解决方法
(1)刚开始设计时没有考虑运用多线程,只是运用主程序运行所有的任务,运行结果虽然也出来了,但是当程序运行时,如果用户稍微在运行中的界面某一处点击的话,立即造成程序死掉的假象,实际上程序在继续运行中,只是不再响应用户的其他任何命令(除退出),等到程序结束的条件为真时才继续响应用户的请求,这样的设计明显是用户不能忍受的,所以在同学的建议下改用多线程设计思想,在主程序运行的同时调用抓包线程函数进行抓包操作,而同时主程序能响应用户的其他一些操作。
(2)程设计原来的要求是让用户进行时间设定,用户设定的时间未到,程序不能停止,这样的设计不太人性化,后来改成有开始与停止按钮,随时响应用户的开始与停止的命令
参考文献
[1]吴功宜胡小英张仁何云王宁.计算机网络课程设计.机械工业出版社,2007.12
[2]求是科技谭思亮.监听与隐藏.人民邮电出版社,2002.8
[3]胡海生李升亮.VisualC++6.0编程学习捷径.清华大学出版社,2003.10