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 96795 110.247.139.26:27234 1403334343:455958 1403334343:508050 52092 110.73.32.219:6289 1403334249:379281 1403334249:438474 59193 111.206.126.81:5829 1403334279:983416 1403334280:107169 -875247//由该行看书第二部分时间达到10^6后,进位到第一部分时间,
112.132.132.243:28525 1403334268:430188 1403334268:734291 304103 112.81.95.111:tksocket 1403334206:465030 1403334206:525732 60702 112.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
最常见的有两种
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 <map> using namespace std; typedef short _Int16; typedef unsigned short u_Int16; typedef unsigned long _Int32; typedef char _Int8; typedef char Byte; struct __file_header { _Int32 iMagic; _Int16 iMaVersion; _Int16 iMiVersion; _Int32 iTimezone; _Int32 iSigFlags; _Int32 iSnapLen; _Int32 iLinkType; }; struct __pkthdr { _Int32 iTimeSecond; _Int32 iTimeSS; _Int32 iPLength;/* length of portion present */ _Int32 iLength; /* length this packet (off wire) */ }; struct FrameHeader_t { _Int8 DstMAC[6]; _Int8 SrcMAC[6]; _Int16 FrameType; }; struct IPHeader_t { _Int8 Ver_HLen; _Int8 TOS; _Int16 TotalLen; _Int16 ID; _Int16 Flag_Segment; _Int8 TTL; _Int8 Protocal; _Int16 Checksum; _Int32 SrcIP; _Int32 DstIP; }; struct TCPHeader_t { u_Int16 srcPort; u_Int16 dstPort; _Int32 sequence_num; _Int32 ACK_num; _Int8 dataoffset; //4 bit offset +4 bit reserved _Int8 flag; //2 bits reserved+6 bits flag u_Int16 wind; u_Int16 checksum; u_Int16 urgent_point; }; struct UDPHeader_t { _Int16 srcPort; _Int16 dstPort; _Int16 Length; _Int16 Checksum; }; //void readpcap(); void read_analse_pcap_tcp(); void read_analse_pcap_udp(); extern map<string,string> peer; #endif
/**对每个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!"<<endl; return ; } string tcpline,tcpword; vector<string> 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:"<<sizeof(data)<<endl; struct __file_header header; struct FrameHeader_t ethernethdr; struct IPHeader_t ipheader,ipheader1; struct TCPHeader_t tcpheader,tcpheader1; FILE* pFile = fopen( pcapfilename.c_str(), "rb"); if(pFile==0) { cout<<"open pcap file failed!"<<endl; return ; } fseek(pFile,0,SEEK_END); long iFileLen=ftell(pFile); fseek(pFile,0,SEEK_SET); Byte * pBuffer=new Byte[iFileLen]; fread((void*)pBuffer,1,iFileLen,pFile); fclose(pFile); Byte * tcpbytes=new Byte[20]; for(vector<string>::iterator it=cdn_ip_list.begin();it!=cdn_ip_list.end();it++) { cout<<"*it"<<*it<<endl; //cin>>x; ofstream outfile("F:\\RTMFP\\measurement data\\ME4\\"+*it+".txt"); if(outfile==0) { cout<<"*it file open failed!"<<endl; } int iIndex=sizeof(struct __file_header); int iNo=1; cout<<"iFileLen:"<<iFileLen<<endl; unsigned int initseqin=0,initseqout=0; int count=0; 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<<count<<":count"<<endl; cout<<ipheaderlen<<":ipheaderlen"<<endl; cout<<"iphd.."<<sizeof(struct IPHeader_t)<<endl; cout<<longtoip(ipheader.SrcIP)<<"--->"<<longtoip(ipheader.DstIP)<<endl; memcpy((void*)&tcpheader,(void*)(pBuffer+iIndex+sizeof(struct __pkthdr)+sizeof(struct FrameHeader_t)+ipheaderlen*4),sizeof(struct TCPHeader_t)); /**要注意网络字节与主机字节的转换**/ cout<<(int)(tcpheader.flag)<<":tcpheader.flag"<<endl; memcpy((void*)tcpbytes,(void*)(pBuffer+iIndex+sizeof(struct __pkthdr)+sizeof(struct FrameHeader_t)+ipheaderlen*4),20); cout<<int(tcpbytes[4])<<" "<<int(tcpbytes[5])<<" "<<int(tcpbytes[6])<<" "<<int(tcpbytes[7])<<" "<<int(tcpbytes[8])<<endl; // cin>>x; if(tcpheader.flag==2) { if(longtoip(ipheader.SrcIP)==*it) { initseqin=ntohl(tcpheader.sequence_num); outfile<<"host<-----"<<*it<<" 0 * "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; //initseqout=tcpheader.sequence_num; } else if(longtoip(ipheader.DstIP)==*it) { initseqout=ntohl(tcpheader.sequence_num); outfile<<"host----->"<<*it<<" 0 * "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; //initseqin=tcpheader.sequence_num; } } else if(tcpheader.flag==18) { if(longtoip(ipheader.SrcIP)==*it) { initseqin=ntohl(tcpheader.sequence_num); outfile<<"host<-----"<<*it<<" 0 1 "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; //initseqout=tcpheader.sequence_num; } else if(longtoip(ipheader.DstIP)==*it) { initseqout=ntohl(tcpheader.sequence_num); outfile<<"host----->"<<*it<<" 0 1 "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; // initseqin=tcpheader.sequence_num; } iIndex+=sizeof(struct __pkthdr)+data.iPLength; break; } } } iIndex+=sizeof(struct __pkthdr)+data.iPLength; } cout<<initseqin<<" init "<<initseqout<<endl; //cin>>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::"<<count<<endl; memcpy((void*)&tcpheader,(void*)(pBuffer+iIndex+sizeof(struct __pkthdr)+sizeof(struct FrameHeader_t)+ipheaderlen*4),sizeof(struct TCPHeader_t)); if(longtoip(ipheader.SrcIP)==*it) { outfile<<"host<-----"<<*it<<" "<<ntohl(tcpheader.sequence_num)-initseqin<<" "<<ntohl(tcpheader.ACK_num)-initseqout<<" "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; } else { outfile<<"host----->"<<*it<<" "<<ntohl(tcpheader.sequence_num)-initseqout<<" "<<ntohl(tcpheader.ACK_num)-initseqin<<" "<<ntohs(tcpheader.wind)<<" "<<int(tcpheader.flag)<<endl; } } } iIndex+=sizeof(struct __pkthdr)+data.iPLength; } cout<<*it<<" end--"<<endl; cin>>x; } }