【以太网数据结构】IP协议

IP协议数据包格式:

【以太网数据结构】IP协议_第1张图片

IP协议最终目的是把数据从源传送到目的地,它不保证数据传送的靠性性!
主要作用:

  • 数据传送:将数据从一个主机传到另一个主机
  • 寻址:根据子网划分IP地址,发现正确的目的主机地址
  • 路由选择:选择数据在互联网上的传送路径
  • 数据报文的分段:当传送的数据大于MTU时,将数据进行分段发送和接收并组装

协议字段解释:

  • 版本:IP协议版本号,长度为4位。对于IPV4,此处值为4;对于IPV6为6。
  • 首部长度:4位,代表IP头部长度,该值 x 4 = 首部占用字节数。
  • 服务类型:8位,该字段现在基本没什么作用,通常设为0x00。
  • 总长度:16位(IP报文最大数据长度为65535字节),表示以字节为单位的数据报文长度,长度包含IP的头部和数据部分。
  • 标识和片偏移:IP每发送一份数据报文后都会将此值+1。当一份报文数据大于MTU(最大传输单元,一般为1500)时就会进行分片,所分的片用片偏移记录,以便重组,由于这些分片属于同一份IP数据,故标识相同,片偏移不同。
    现在TCP协议传输数据时会将数据分段,分的段足够小(一般<=1460),以至于数据到达IP层封装的时候不足以让IP分片,知道为什么会这样吗?
    因为IP协议不保证数据传送的靠性性!当一份IP数据的某个小分片丢失时(事实上数据包丢失的情况非常常见),整个IP报文都得重传!!!TCP协议事先在三次握手的过程中协商了MSS值(最大TCP分段大小),将设置MSS值小于等于1460,这样大大降低了数据重传所付出的代价。

  • 生存时间TTL:8位,该字段的值表示数据报文组多可以经过的路由器的数量。该字段很有意思,每经过一个路由器,TTL的值会减1,当TTL的值为0时,路由器会将该数据包丢弃,以防止该包在网络中不断循环,当然路由器丢弃该数据包时会发送一个ICMP报文通知源主机。

  • 协议类型:8位,表示IP上承载的是什么协议,见下表:
协议类型 协议类型
1 ICMP 6 TCP
2 IGMP 17 UDP
  • 头部校验和:16位,只对IP头部进行校验。接收方接收到数据后也会对数据进行校验,然后和该字段进行比对,如果不匹配则表示此帧数据发生错误。由于数据每经过一个路由器都会更改TTL值,所以路由器要重新对IP包头进行校验。
  • 源地址和目的地址:分别表示发送数据的主机和接收数据的主机的IP地址。
  • IP选项:该字段一般为空,很少用到,不解释。

相关源代码
再linux/ip.h文件中,ip包头结构体定义如下:

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u8    ihl:4,
        version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
    __u8    version:4,
        ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
    __u8    tos;
    __be16  tot_len;
    __be16  id;
    __be16  frag_off;
    __u8    ttl;
    __u8    protocol;
    __sum16 check;
    __be32  saddr;
    __be32  daddr;
    /*The options start here. */
};

获取ip包头结构体函数:

#ifdef __KERNEL__
#include <linux/skbuff.h>

static inline struct iphdr *ip_hdr(const struct sk_buff *skb)//常用
{
    return (struct iphdr *)skb_network_header(skb);
}

static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) 
//TCP头,在数据包未拆封之前,sk_buff结构体成员TCP头指针可能和IP头指针指向同一个位置
{
    return (struct iphdr *)skb_transport_header(skb);
}
#endif

你可能感兴趣的:(以太网,TCP-IP协议)