http://wenku.baidu.com/link?url=BkRDW0md1bM_MRfJVykSTu7_Ppe4mj1Zauxfmb9_gvCFPohUpa59m-IbEq2DWGLmTr1kW_-dkAGCAIOpBhUTk6ormkcfj8vU-Zl-My4MQ9a
该网页内容基本已经够用,下面是一些需要修改或注意的地方。
1.
struct pcap_pkthdr
{
struct timeval ts; ts是一个结构struct timeval,它有两个部分,第一部分是1900开始以来的秒数,第二部分是当前秒之后的毫秒数
//我的经验是微妙,即第二部分达到1000000,前部分加1.
bpf_u_int32 caplen; 表示抓到的数据长度
bpf_u_int32 len; 表示数据包的实际长度
}
以下是我部分程序结果:第二列是发送给IP(第一列的第一个udp包的时间),第三列是在发送包后从IP接收到的第一个udp包的时间,第三列是后者减前者,理论上第三列值为正数,但是出现负数,是因为我计算时先秒数相减*1000,在加上毫秒数,
但实际上应该秒数之差*1000,000 +第二部分时间差。
110.153.127.193:asnaacceler8db 1403334193:459623 1403334203:546418 96795110.247.139.26:27234 1403334343:455958 1403334343:508050 52092110.73.32.219:6289 1403334249:379281 1403334249:438474 59193111.206.126.81:5829 1403334279:983416 1403334280:107169 -875247//由该行看书第二部分时间达到10^6后,进位到第一部分时间, 112.132.132.243:28525 1403334268:430188 1403334268:734291 304103112.81.95.111:tksocket 1403334206:465030 1403334206:525732 60702112.93.191.212:28980 1403334262:448167 1403334262:542576 94409
2. pcap文件的内容是以网络字节,我们读取后使用时要转化成主机字节
linux系统 :#include <arpa/inet.h>
Windows系统 :#include<Winsock2.h>
uint16_t ntohs(uint16_t netshort);//实际作用 输入 二字节 0xoabd,输出0xbdoa,即小端到大端的转换 uint32_t ntohl(uint32_t netlong);
以下内容来自于http://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html
不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序 最常见的有两种 1. Little endian:将低序字节存储在起始地址 2. Big endian:将高序字节存储在起始地址 LE little-endian 最符合人的思维的字节序 地址低位存储值的低位 地址高位存储值的高位 怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说 低位值小,就应该放在内存地址小的地方,也即内存地址低位 反之,高位值就应该放在内存地址大的地方,也即内存地址高位 BE big-endian 最直观的字节序 地址低位存储值的高位 地址高位存储值的低位 为什么说直观,不要考虑对应关系 只需要把内存地址从左到右按照由低到高的顺序写出 把值按照通常的高位到低位的顺序写出 两者对照,一个字节一个字节的填充进去 例子:在内存中双字0x01020304(DWORD)的存储方式 内存地址 4000 4001 4002 4003 LE 04 03 02 01 BE 01 02 03 04 例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为 big-endian little-endian 0x0000 0x12 0xcd 0x0001 0x23 0xab 0x0002 0xab 0x34 0x0003 0xcd 0x12 x86系列CPU都是little-endian的字节序. 网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。 为了进行转换 bsd socket提供了转换的函数 有下面四个 htons 把unsigned short类型从主机序转换到网络序 htonl 把unsigned long类型从主机序转换到网络序 ntohs 把unsigned short类型从网络序转换到主机序 ntohl 把unsigned long类型从网络序转换到主机序 在使用little endian的系统中 这些函数会把字节序进行转换 在使用big endian类型的系统中 这些函数会定义成空宏 同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug. 注: 1、网络与主机字节转换函数:htons ntohs htonl ntohl (s 就是short l是long h是host n是network) 2、不同的CPU上运行不同的操作系统,字节序也是不同的,参见下表。 处理器 操作系统 字节排序 Alpha 全部 Little endian HP-PA NT Little endian HP-PA UNIX Big endian Intelx86 全部 Little endian <-----x86系统是小端字节序系统 Motorola680x() 全部 Big endian MIPS NT Little endian MIPS UNIX Big endian PowerPC NT Little endian PowerPC 非NT Big endian <-----PPC系统是大端字节序系统 RS/6000 UNIX Big endian SPARC UNIX Big endian IXP1200 ARM核心 全部 Little endian
下面贴一部分pcap解析代码:
头文件:
#ifndef PCAP_H#define PCAP_H#include
/**对每个IP地址,分析pcap文件中与该ip地址进行tcp通信的每个tcp数据包的sequence number ,acknumber,wind,flag,结果如wireshark 工具中的statistics的follow graph **/const string pcapfilename="F:\\江苏loss-0.6.pcap";void read_analse_pcap_tcp(){ ifstream tcpinfile(tcpinfilename); if (tcpinfile==NULL) { cout<<"tcpinfile open error!"<cdn_ip_list; istringstream tcplinestream; getline(tcpinfile,tcpline); char *word; char line2[200]; const char* line1; char * leftline; while(getline(tcpinfile,tcpline)) { line1=tcpline.c_str(); strcpy_s(line2,line1); word=strtok_s(line2,",",&leftline); int i=0; while(word!=NULL &&i<2) { word=strtok_s(NULL,",",&leftline); i++; } cdn_ip_list.push_back(string(word)); } struct __pkthdr data ; //struct 声明 即可实例化 cout<<"s data:"< < ::iterator it=cdn_ip_list.begin();it!=cdn_ip_list.end();it++) { cout<<"*it"<<*it< >x; ofstream outfile("F:\\RTMFP\\measurement data\\ME4\\"+*it+".txt"); if(outfile==0) { cout<<"*it file open failed!"< "< < >x; if(tcpheader.flag==2) { if(longtoip(ipheader.SrcIP)==*it) { initseqin=ntohl(tcpheader.sequence_num); outfile<<"host<-----"<<*it<<" 0 * "< <<" "< < "<<*it<<" 0 * "< <<" "< < "<<*it<<" 0 1 "< <<" "< < >x; // iIndex+=sizeof(struct __pkthdr)+data.iPLength; while(iIndex<=iFileLen) { count++; memcpy((void*)&data,(void*)(pBuffer+iIndex),sizeof(struct __pkthdr)); memcpy((void*)ðernethdr,(void*)(pBuffer+iIndex+sizeof(struct __pkthdr)),sizeof(struct FrameHeader_t)); if(ethernethdr.FrameType==8) { memcpy((void*)&ipheader,(void*)(pBuffer+iIndex+sizeof(struct __pkthdr)+sizeof(struct FrameHeader_t)),sizeof(struct IPHeader_t)); if((int)ipheader.Protocal==6&&(longtoip(ipheader.SrcIP)==*it||longtoip(ipheader.DstIP)==*it)) { int ipheaderlen=ipheader.Ver_HLen&15; //cout<<"count22222222222222222::"< < "<<*it<<" "< <<" "< <<" "< <<" "< < >x; }}