之前课设做过一回,然后过了半年不到,又华华丽丽的忘了。。。最近又要用,所以又捡了起来。
首先是环境的准备
首先是安装包 http://download.csdn.net/detail/u013529927/7174089
然后是开发包 http://download.csdn.net/detail/u013529927/7174095
上面的都是最新版的。当然,你也可以去官网上下 http://www.winpcap.org/第一个标签 里面有“Get Winpcap”和"Development"分别对应环境和开发包。
然后安装环境包,一直next就行。。。
然后就可以打开VS了~(因为我用的VS,VC 6.0其实也差不多。。。)
把开发包中的 Include 和 Lib文件夹放到任意一个位置(因为后面都用的绝对路径,所以放哪都无所谓,当然还是推荐工程文件夹下面)
然后在 项目-> (工程名)属性(PS:VS2013里面是最后一个)->配置属性->VC++目录 中在包含目录里面添加 上面 Include文件夹的位置 在库目录里面添加 Lib文件夹的位置。
然后在工程中添加两个文件
第一个是头文件 IPNodeList.h
#include <fstream> #include <iostream> using namespace std; class IPNode { private: long m_lIPAddress; //IP地址 long m_lCount; //发送数据包数 public: IPNode*pNext; //指向下一个IP节点 //构造函数 IPNode(long sourceIP) { m_lIPAddress = sourceIP; m_lCount = 1; //初始化数据包个数为1 } //数据包个数加1 void addCount() { m_lCount++; } //返回数据包个数 long getCount() { return m_lCount; } //返回IP地址 long getIPAddress() { return m_lIPAddress; } }; //节点链表 class NodeList { IPNode*pHead; //链表头 IPNode*pTail; //链表尾 public: NodeList() { pHead = pTail = NULL; } ~NodeList() { if (pHead != NULL) { IPNode*pTemp = pHead; pHead = pHead->pNext; delete pTemp; } } //IP节点加入链表 void addNode(long sourceIP) { IPNode* pTemp; if (pHead == NULL) //当链表为空时 { pTail = new IPNode(sourceIP); pHead = pTail; pTail->pNext = NULL; } else //不为空时 { for (pTemp = pHead; pTemp; pTemp = pTemp->pNext) { //如果链表中存在此IP,发送数据包个数加1 if (pTemp->getIPAddress() == sourceIP) { pTemp->addCount(); break; } } //如果链表中没有此IP,则加入链表 if (pTemp == NULL) { pTail->pNext = new IPNode(sourceIP); pTail = pTail->pNext; pTail->pNext = NULL; } } } //输出IP结点,即IP地址和其它发送的IP包个数 ostream& print(ostream& os) { for (IPNode*pTemp = pHead; pTemp; pTemp = pTemp->pNext) { long lTemp = pTemp->getIPAddress(); os << inet_ntoa(*(in_addr*)&(lTemp)) << ‘\t‘; os << pTemp->getCount() << endl; } return os; } };
第二个 因为是cpp文件,所以文件名随便起一个就行~
#include <iostream> #include <iomanip> #include <fstream> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include "pcap.h" #include "IPNodeList.h" //等同于点击“Project→Setting→link"打开object/library modules编辑框后加入lib文件 #pragma comment(lib,"Wpcap.lib") #pragma comment(lib,"Ws2_32.lib") using namespace std; //IP包的头部结构 struct ip_header{ unsigned char ver_ih1; //版本号(4位)+头部长度(4位) unsigned char tos; //服务类型 unsigned short tlen; //总长度 unsigned short identification; //标识 unsigned short flags_fo; //标志+片偏移 unsigned char tt1; //生存时间 unsigned char proto; //协议 unsigned short crc; //校检和 DWORD saddr; //源地址 DWORD daddr; //目的地址 unsigned int op_pad; //选项+填充 }; void main(int argc, char*argv[]) { if (argc != 3) //判断参数是否正确 { cout << "Usage:IPStatistic time logfile" << endl; cout << "Press any key to continue…" << endl; _getch(); return; } double sec = atof(argv[1]); pcap_if_t *alldevs; //网络设备结构 pcap_if_t *d, *head = NULL; pcap_t *fp; //网卡描叙符 char errbuf[PCAP_ERRBUF_SIZE]; //错误信息 unsigned int netmask; //子网掩码 char packet_filter[] = "ip"; //过滤,选择IP协议 struct bpf_program fcode; struct pcap_pkthdr *header; const unsigned char *pkt_data; //获取网络设备列表 if (pcap_findalldevs(&alldevs, errbuf) == -1) { cout << "Error in pcap_findalldevs : " << errbuf; return; } int i = 1; //网卡数 if (i == 0) //无设备 { cout << "\nNo interfaces found!Make sure winPacp is installed.\n"; return; } if (i >= 1) { int j = 0; for (d = alldevs; d; d = d->next) //列出网卡列表,让用户进行选择 { cout << ++j << ":" << d->name; if (d->description) cout << " " << d->description << endl; } cout << "\nEneter the interface number(1 - " << j << ") :"; int k; cin >> k; if (k<1 || k>j) { cout << "out of range" << endl; return; } for (d = alldevs, i = 1; i<k; d = d->next, i++); //找到选择的网卡 head = d; } //以混杂模式打开网卡 if ((fp = pcap_open_live(head->name, 1000, 1, 1000, errbuf)) == NULL) { cout << "\nUnable to open the adapter." << endl; pcap_freealldevs(alldevs); return; } //获得子网掩码 if (head->addresses != NULL) netmask = ((sockaddr_in*)(head->addresses->netmask))->sin_addr.S_un.S_addr; else //没有地址假设为C类地址 netmask = 0xffffff; //编译过滤器 if (pcap_compile(fp, &fcode, packet_filter, i, netmask)<0) { cout << "\nUnable to compile the packet filter.Check the syntax.\n"; pcap_freealldevs(alldevs); return; } //设置过滤器 if (pcap_setfilter(fp, &fcode)<0) { cout << "\nEeeor setting the filter.\n"; pcap_freealldevs(alldevs); return; } //显示提示信息及每项含义 cout << "\t\tlistening on " << head->description << " " << endl << endl; ofstream fout(argv[2], ios::app); //日志记录文件 fout << "\tIP Statistic : (" << sec << "minutes)" << endl; time_t tmp = time(NULL); fout << ctime(&tmp); cout << "IP Statistic : (" << sec << "Seconds)" << endl; fout << " Sour IP " << "\tpacket numbers" << endl; //释放设备列表 pcap_freealldevs(alldevs); NodeList link; //存储数据用链表 int res; time_t beg; time_t end; time(&beg); //获得当前时间 while ((res = pcap_next_ex(fp, &header, &pkt_data)) >= 0) { time(&end); //获得系统时间 if (end - beg >= sec) //计算系统时间 break; if (res == 0) continue; //超时 ip_header*ih; //找到IP头位置 ih = (ip_header*)(pkt_data + 14); //14为以太头的长度 link.addNode(ih->saddr); //将源IP地址假如链表 } cout << "Sour IP " << ‘\t‘ << "packet numbers" << endl; link.print(cout); //输出到屏幕 link.print(fout); //输出到日志文件 fout << endl; }
要说明的一点是:上面的cpp文件中有一行 fout << ctime(&tmp); 这个是在文件中输出记录时间的 如果要用这个要在 项目属性 -> 配置属性->C/C++ ->命令行中的其它选项中添加/D _CRT_SECURE_NO_WARNINGS 如果有强迫症的同学就直接把这个注释了吧-_-||
最后一步,在项目属性 -> 配置属性->调试中的命令参数中填参数 第一个是时间 单位是秒,第二个是记录文件的名称 例如 "10 1.txt"(PS:去掉引号)
然后运行就行了,第一步是选择网卡,然后静静地等待出结果就行了~