ip数据包格式

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
IP数据包格式详解
2011-12-21 09:58:57| 分类: 网络协议 | 标签: |字号大中小 订阅
TCP/IP协议定义了一个在因特网上传输的包,< xmlnamespace prefix ="o" ns ="urn:schemasmicrosoft-com:office:office" /> 称为IP数据报 (IP Datagram)。这是一个与硬件无关的虚拟包, 由首部和数据两部分组成。首部的前一部分是固定长度,共 20 字节, 是所有IP数据报必须具有的。在首部的固定部分的后面是一些可选字段, 其长度是可变的。首都中的源地址和目的地址都是 IP 协议地址。 那么IP数据报格式又是怎样要求的呢? 1. IP数据报首部的固定部分中的各字段 ①版本:占4位,指IP协议的版本。通信双方使用的
IP协议版本必须一致。日前广泛使用的 IP协议版本号为 4 (即 IPv4)。 IPv6 目前还处于起步阶段。 ②首部长度:占 4 位,可表示的最大十进制数值是 15。请注意, 这个字段所表示数的单位是32位字 ( 1 个32位字长是4 字节), 因此,当 IP 的首部长度为 1111 时 (即十进制的 15), 首部长度就达到 60字节。当 IP 分组的首部长度不是4字节的整数倍时, 必须利用最后的填充字段加以填充。 因此数据部分永远在 4字节的整数倍开始, 这样在实现 IP协议时较为方便。 首部长度限制为 60字节的缺点是有时可能不够用。 这样做的目的是希望用户尽量减少开销。 最常用的首部长度就是 20 字节 (即首部长度为 0101), 这时不使用任何选项。 ③服务:占 8 位,用来获得更好的服务。 这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。 1998年IETF把这个字段改名为区分服务 DS (DifferentiatedServices)。 只有在使用区分服务时,这个字段才起作用。 ④总长度:总长度指首都及数据之和的长度,单位为字节。 因为总长度字段为 16位,所以数据报的最大长度为 216-1=65 535字节。 在IP层下面的每一种 数据链路层都有自己的帧格式,其中包括帧格式中的数据字段的最大长度,即最大传送单元 MTU (Maximum Transfer Unit)。当一个数据报封装成链路层的帧时,此数据报的总长度 (即首部 加上数据部分)一定不能超过下面的数据链路层的MTU值。 ⑤标识 (Identification):占 16位。 IP软件在存储器中维持一个计数器,每产生一个数据报, 计数器就加 1,并将此值赋给标识字段。但这个“标识”并不是序号, 因为 IP是无连接的服务,数据报不存在按序接收的问题。 当数据报由于长度超过网络的 MTU 而必须分片时, 这个标识字段的值就被复制到所有的数据报的标识字段中。 相同的标识字段的值使分片后的各数据报片最后能正确地重装成为 原来的数据报。 ⑥标志 (Flag):占3 位,但目前只有2位有意义。 标志字段中的最低位记为 MF (More Fragment)。 MF=1即表示后面“还有分片”的数据报。MF=0表示这已是若干数据报片 中的最后一个。 标志字段中间的一位记为 DF(Don't Fragment), 意思是“不能分片”。只有当 DF=0时才允许分片。 ⑦片偏移:占 13位。较长的分组在分片后, 某片在原分组中的相对位置。也就是说,相对用户数据字段的起点, 该片从何处开始。片偏移以 8个字节为偏移单位。 这就是说,每个分片的长度一定是 8字节 (64位)的整数倍。 ⑧生存时间:占 8位,生存时间字段常用的英文缩写是 TTL (Time To Live),其表明数据报在网络中的寿命。 由发出数据报的源点设置这个字段。 其目的是防止无法交付的数据报无限制地在因特网中兜围子, 因而白白消耗网络资源。最初的设计是以秒作为 TTL的单位。 每经过一个路由器时,就把TTL减去数据报在路由器消耗掉的一段时间。 若数据报在路由器消耗的时间小于 1 秒,就把TTL值减 1。 当 TTL值为 0时,就丢弃这个数据报。 ⑨协议:占 8 位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP 层知道应将数据部分上交给哪个处理过程。
源自文库
void AutoWSACleanup() { ::WSACleanup(); } int main() { //初始化winsock库,使用2.2版本 u_short wVersionRequested = 0x0202; WSADATA wsaData; if( SOCKET_ERROR == WSAStartup( wVersionRequested, &wsaData ) ) { cout << WSAGetLastError(); return 0; } atexit( AutoWSACleanup ); //创建SOCKET SOCKET h = socket( AF_INET, SOCK_RAW, IPPROTO_IP); if( h == INVALID_SOCKET ) { cout << WSAGetLastError(); return 0; } //获取本机地址 char FAR name[128]; if( -1 == gethostname(name, sizeof(name)) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } struct hostent FAR * pHostent;
int DecodeIP(char *buf, int len) { int n = len; if( n >= sizeof(IP_PK_HEAD) ) { IP_PK_HEAD iphead; memcpy( &iphead, buf, sizeof(iphead) ); //以下三个为Big Endian字节顺序,转换成主机字节顺序 iphead.wPacketLen = ntohs( iphead.wPacketLen ); iphead.wSequence = ntohs( iphead.wSequence ); iphead.wHeadCheckSum = ntohs( iphead.wHeadCheckSum ); in_addr src,dst; src.S_un.S_addr = iphead.dwIPSrc; dst.S_un.S_addr = iphead.dwIPDes; char strsrc[20],strdst[20]; strcpy(strsrc, inet_ntoa(src)); strcpy( strdst , inet_ntoa(dst)); printf( "IP数据包: ver=%d,hlen=%d,protocol=%d,pklen=%d,seq=%d,src=%s,dst=%s _fcksavedurl=%s,dst=%s", iphead.ver_hlen >> 4, (iphead.ver_hlen & 0x0F) << 2, iphead.byProtocolType, iphead.wPacketLen, iphead.wSequence, strsrc, strdst ); } return 0; }
pHostent = gethostbyname(name); //绑定本地地址到SOCKET句柄 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr = *(in_addr*)pHostent->h_addr; //IP addr.sin_port = 0; //端口,IP层端口可随意填 if( SOCKET_ERROR == bind( h,(sockaddr *)&addr,sizeof(addr) ) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } //设置该SOCKET为接收所有流经绑定的IP的网卡的所有数据,包 括接收和发送的数据包 //该函数在mstcpip.h里面,详见MSDN帮助 u_long sioarg = 1; DWORD wt=0; if( SOCKET_ERROR == WSAIoctl( h, SIO_RCVALL , &sioarg,sizeof(sioarg),NULL,0,&wt,NULL,NULL ) ) { closesocket( h ); cout << WSAGetLastError(); return 0; } //我们只需要接收数据,因此设置为阻塞IO,使用最简单的IO模 型 u_long bioarg = 0; if( SOCKET_ERROR == ioctlsocket( h, FIONBIO , &bioarg ) ) { closesocket( h ); cout << WSAGetLastError(); return 0;
//IP首部 typedef struct tIPPackHead { enum PROTOCOL_TYPE{ PROTOCOL_TCP = 6, PROTOCOL_UDP = 17, PROTOCOL_ICMP = 1, PROTOCOL_IGMP = 2 }; inline unsigned HeadLen() const { //首部长度单位为4bytes。因此乘4 return (ver_hlen & 0x0F) << 2; } inline unsigned PackLen() const { return wPacketLen; } BYTE ver_hlen; //IP协议版本和IP首部长度。高4位为版 本,低4位为首部的长度(单位为4bytes) BYTE byTOS; //服务类型 WORD wPacketLen; //IP包总长度。包括首部,单位为byte。 [Big endian] WORD wSequence; //序号,一般每个IP包的序号递增。[Big endian] WORD wMarkFragPoi; BYTE byTTL; //生存时间 BYTE byProtocolType; //协议类型,见PROTOCOL_TYPE定义 WORD wHeadCheckSum; //IP首部校验和[Big endian] DWORD dwIPSrc; //源地址 DWORD dwIPDes; //目的地址 } IP_PK_HEAD; int DecodeIP(char *buf, int len);
⑩首部检验和:占 16位。这个字段只检验数据报的首部, 但不包括数据部分。这是因为数据报每经过一个路由器,都要重新计算一下首都检验和 (一些字 段,如生存时间、标志、片偏移等都可能发生变化)。不检验数据部分可减少计算的工作量。 ⑾源地址:占32位。 ⑿目的地址:占 32位。 2. IP数据报首部的可变部分 IP首都的可变部分就是一个可选字段。选项字段用来支持排错、测量以及安全等措施,内容 很丰富。此字段的长度可变,从 1 个字节到40个字节不等,取决于所选择的项目。某些选项只 需要 1 个字节,它只包括 1 个字节的选项代码。但还有些选项需要多个字节,这些选项一个个 拼接起来,中间不需要有分隔符,最后用全0 的填充字段补齐成为 4字节的整数倍。 增加首都 的可变部分是为了增加 IP 数据报的功能,但这同时也使得 IP 数据报的首部长度成为可变的。 这就增加了每一个路由器处理数据报的开销。实际上这些选项很少被使用。新的 IPv6就将 IP数 据报的首部长度做成固定的。 IP数据包指的是第三层的PDU, IP首部只是其中的一部分,是在第三层网络层上加上去的,是给路由器看的。 IP数据包的总长度过大,超过链路的最大MTU时,数据包就会被分成多片, 而在如今的IPv4的网络中,数据传输时不可靠的,是尽力而为的, 所以这些分片的数据单元到达对端的链路和时间都是不同的, 对端根据IP首部中的标示符(Identification)、标志(Flag)、段偏置值字段 重组数据包。
IP数据包包含 tcp数据包 udp数据包 tcp传输建立的是管道,udp发送的是广播
#include <winsock2.h> #include <windows.h> #include <mstcpip.h> #pragma comment(lib,"Ws2_32.lib") #include <iostream> using namespace std;
相关文档
最新文档