监控IP包流量05062124吴文强.docx
《监控IP包流量05062124吴文强.docx》由会员分享,可在线阅读,更多相关《监控IP包流量05062124吴文强.docx(14页珍藏版)》请在冰豆网上搜索。
监控IP包流量05062124吴文强
南昌航空大学计算机学院
课程设计说明书
课程名称:
计算机网络课程设计
设计题目:
监控IP包流量
专业:
网络工程班级:
050621
姓名:
吴文强学号:
24
评分:
指导教师:
周之平邓林生
2008年6月29日
一.课程设计目的
随着Internet技术的发展,基于IP协议的网络应用成为网络技术研究与软件开发的一个重要基础,因此学习网络层的基本概念,了解IP协议的基本内容,对于掌握TCP/IP协议的主要内容和学习网络课程是十分重要的。
通过本课程设计,有助于熟悉IP包格式和加深对IP协议的理解。
二.需求分析
1.编制程序,监控网络,捕获一段时间内网络上IP数据包,按IP数据包的源地址统计出该源地址在该时间内发出的IP包个数,将其写入日志文件中或用图形表示出来。
2.设计可视化图形界面,可以进行捕获操作和停止操作,并且捕获完成后有统计结果显示和日志文件生成。
3.程序设计采用C++或者Java(本次设计决定采用C++)。
三.概要设计
本次课程设计的主要目的是接收统计IP包,所以主要任务就是设置网卡以及相关的一系列操作,而图形界面的设计要求次之,所以主要介绍下我门对接收统计IP包的一些设计:
定义一些用于存储所要记录的源地址和该源地址发出的包的个数的结构体以及链表;
主要是查找网卡,设置网卡为混杂模式,编辑过滤器,设置过滤器;
捕获IP数据包并按包的源地址进行统计(存入链表中)。
程序流程图如下:
图1程序流程图
四.详细设计及编码
(1)新建一个基于对话框的MFCAppWizard[exe]工程,取名为IPStatistic。
在IDD_IPSTATISTIC_DIALOG中加入界面所需要的控件,所加的控件从上到下依次有静态文本取名为网卡列表,下拉列表框(定义变量为m_comboboxx),静态文本取名为捕获包个数,静态文本(设置ID为IDC_CLOCK,用于显示捕获的包个数),开始捕获按钮,停止按钮,退出按钮,静态文本(设置ID为IDC_STATE,用于表示当前状态),一个组合框(取名为统计结果如下:
),一个清空列表按钮,最后一个是列表控制框(用于显示最后捕获的数据统计),此时的界面如下图:
图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;//链表尾
public:
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->pNext;
pTail->pNext=NULL;
}
}
}
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"
#include"IPStatisticDlg.h"
#include"IPNodeList.h"
#include
#include
#include
#include
#include
#include
#include"pcap.h"
#pragmacomment(lib,"Wpcap.lib")
#pragmacomment(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!
=NULL)
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设置过滤器失败!
\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)->EnableWindow(false);//网卡列表不可用
GetDlgItem(IDC_BUTTON1)->EnableWindow(false);//开始捕获按钮不可用
GetDlgItem(IDC_BUTTON3)->EnableWindow(true);//停止按钮变为可用
m_listcontrol.DeleteAllItems();
capstop=true;//信号量赋值
cap=AfxBeginThread((AFX_THREADPROC)Threadcap,NULL);//创建线程并立即执行
}
(9)停止按钮代码:
voidCIPStatisticDlg:
:
OnButton3()
{GetDlgItem(IDC_STATE)->SetWindowText("已停止捕获!
");//显示当前状态
GetDlgItem(IDC_COMBO1)->EnableWindow(true);//网卡列表可用
GetDlgItem(IDC_BUTTON1)->EnableWindow(true);//开始捕获按钮可用
GetDlgItem(IDC_BUTTON3)->EnableWindow(false);//停止按钮不可用
capstop=false;//发送信号,终止线程
ofstreamfout("login.txt",ios:
:
app);//日志记录文件
fout<<"\t捕获IP包记录如下:
"<fout<<"开始时间为:
";
time_ttmp=time(NULL);
fout<fout<<"SourIP"<<"\tpacketnumbers"<chartmpstr[50];//临时存储输出字符用的字符数组
for(IPNode*pTemp=link.GetpHead();pTemp;pTemp=pTemp->pNext)//输出结果到日志与列表
{longlTemp=pTemp->getIPAddress();
longr=pTemp->getCount();
fout<fout<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)退出按钮代码:
voidCIPStatisticDlg:
:
OnButton2()//退出按钮
{PostQuitMessage(0);
}
(11)清空按钮代码:
voidCIPStatisticDlg:
:
OnButton4()
{
m_listcontrol.DeleteAllItems();//清空列表控制框
}
五.系统调试与测试
(一)程序的运行
(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