// 司马华鹏
TCP/IP的整个数据包在数据链路层的结构为:
Ethernet Header IP Header TCP/UDP/ICMP/IGMP Header Data
IP 头结构:
版本(4位) 头长度(4位) 服务类型(8位) 封包总长度(16位)
封包标识(16位) 标志(3位) 片断偏移地址(13位)
存活时间(8位) 协议(8位) 校验和(16位)
来源 IP 地址(32位)
目的 IP 地址(32位)
选项(如果有) 填充(如果需要)
数据
C 定义:
typedef struct _IP_HEADER
{
struct
{
BYTE HeaderLength : 4;
BYTE Version : 4;
};
BYTE TypeOfService;
WORD DatagramLength;
WORD Id;
WORD FlagsAndFragmentOffset;
BYTE TimeToLive;
BYTE Protocol;
WORD CheckSum;
BYTE SourceIp[4];
BYTE DestinationIp[4];
} IP_HEADER, *PIP_HEADER;
注意:字节与数字的存储顺序是,从右到左 = 从低位到高位;而网络存储顺序是:从左到右 = 从低位到高位。所以定义数据结构的时候一定要注意字节顺序。
版本(Version):占第一个字节的高四位。比如:IPv4,则这个值为 4。
头长度(HeaderLength):占第一个字节的低四位,头长度表示的是IP头的DWORD个数,如果要转化为字节个数需要乘以 4。比如:IPv4 的头长度为20个字节,这个值为 5。
服务类型:前3位为优先字段权,现在已经被忽略。接着4位为TOS字段,用来表示最小延迟、最大吞吐量、最高可靠性和最小费用。关于服务类型更详细的介绍,请参阅 RFC1340,RFC1349 对以前的 RFC 进行了修正,并更为详细的描述了 TOS 的特性。
封包总长度(DatagramLength):整个 IP 报的长度,单位为字节。
封包标识(Id):唯一标识发送的每一个数据报,通常发送一个加一。
存活时间(TimeToLive):就是TTL,封包的生存时间。通常用通过的路由器个数来衡量,比如初始值设为32,则每通过一个路由器处理,就会被减一,当这个值为0时丢弃这个包,并用ICMP消息通知源主机。
协议(Protocol):定义如下:
#define PROTOCOL_TCP 0x06 // TCP
#define PROTOCOL_UDP 0x11 // UDP
#define PROTOCOL_ICMP 0x01 // ICMP
#define PROTOCOL_IGMP 0x02 // IGMP
校验和(CheckSum):校验和的计算方法为,首先将校验和字段置0,然后将IP头的每16位进行二进制取反求和,将结果保存在校验和字段。验证的方法是安装相同的方法取反求和,得到的结果应该是每一位都是1,如果发生又不是1的位,说明数据传输出错,这时丢包并要求重发。
来源IP地址(SourceIp):来源IP地址,为网络字节顺序。如果将IP看作是32位数值,则需要将网络字节顺序转化为主机字节顺序。转化方法就是,4个字节收尾互换,2、3字节互换。参考代码请参阅 PACKET.C 的 ntohl 函数。
目的IP地址(SourceIp):目的 IP 地址。结构与来源IP地址相同。