IP 协议(Internet Protocol),又称之为网际协议,属于网络层。IP协议以IP地址作为唯一识别码,负责将数据从源主机发送到目标主机。
IP 协议是一种无连接的不可靠数据报交付协议,协议本身不提供任何的错误检查与恢复机制。
在互联网中,每一个主机都有一个唯一的IP地址作为身份识别标志。
(1)分类编址
IP地址可分为五类:A类、B类、C类、D类、E类,其组成如下图。
各类IP地址的特点,如下图。
(2)特殊IP地址
特殊IP地址用于特殊用途,不能分配给任何一个网络的主机使用。
受限广播地址 | 网络号、主机号全为1的地址(255.255.255.255),表示整个互联网内的主机。但是由于路由器禁止转发IP地址为255.255.255.255的数据包,这样的数据包只会在局域网内广播。 |
直接广播地址 | 主机号全为1的地址,表示局域网内的所有主机, |
多播地址 | D类地址属于多播地址,一个发送者,多个接收者。D类地址只能作为目标IP地址,不能作为源IP地址。 |
环回地址 | A类地址中,127网段的所有地址都是环回地址,用来测试网络协议是否正常工作。譬如,ping 127.1.1.1可以测试本地TCP/IP协议是否正常工作。 |
本网络本主机 | IP地址全为0的地址(0.0.0.0),表示本网络本主机。该地址只能作为源地址,用于本机IP地址不明确的情况。 |
局域网(Local Area Network,缩写为 LAN),又称内网,覆盖局部区域的计算机网络。
广域网((Wide Area Network,缩写为 WAN),又称外网、公网,连接不同区域的计算机网络进行通信。
互联网,由无数个局域网,通过广域网线路汇聚互联形成。
局域网、广域网、互联网三者间关系如下图所示。
示例:
P.S.:IPv4和IPv6的报文格式不同,此处记录的为IPv4报文格式。
LWIP定义了ip_hdr结构体来描述IP报文的首部,同时定义了获取IP报文首部信息的宏定义、设置IP报文首部信息的宏定义。源码位置:lwip_2_1_2/src/core/ipv4/ip4_frag.c
定义ip_hdr结构体时要禁止编译器进行对齐操作,因为该结构体的很多字段都是按位进行操作的。
1 PACK_STRUCT_BEGIN 2 struct ip_hdr 3 { 4 /* 版本 / 首部长度 */ 5 PACK_STRUCT_FLD_8(u8_t _v_hl); 6 /* 服务类型 */ 7 PACK_STRUCT_FLD_8(u8_t _tos); 8 /* 数据报总长度 */ 9 PACK_STRUCT_FIELD(u16_t _len); 10 /* 标识字段 */ 11 PACK_STRUCT_FIELD(u16_t _id); 12 /* 标志与偏移 */ 13 PACK_STRUCT_FIELD(u16_t _offset); 14 #define IP_RF 0x8000U /* 保留的标志位 */ 15 #define IP_DF 0x4000U /* 不分片标志位 */ 16 #define IP_MF 0x2000U /* 更多分片标志 */ 17 #define IP_OFFMASK 0x1fffU /* 用于分段的掩码 */ 18 /* 生存时间 */ 19 PACK_STRUCT_FLD_8(u8_t _ttl); 20 /* 上层协议*/ 21 PACK_STRUCT_FLD_8(u8_t _proto); 22 /* 校验和 */ 23 PACK_STRUCT_FIELD(u16_t _chksum); 24 /* 源 IP 地址与目标 IP 地址 */ 25 PACK_STRUCT_FLD_S(ip4_addr_p_t src); 26 PACK_STRUCT_FLD_S(ip4_addr_p_t dest); 27 } PACK_STRUCT_STRUCT; 28 PACK_STRUCT_END 29 30 31 /* 获取 IP 数据报首部各个字段信息的宏 */ 32 33 //获取协议版本 34 #define IPH_V(hdr) ((hdr)->_v_hl >> 4) 35 //获取首部长度(字) 36 #define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) 37 //获取获取首部长度字节 38 #define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4)) 39 //获取服务类型 40 #define IPH_TOS(hdr) ((hdr)->_tos) 41 //获取数据报长度 42 #define IPH_LEN(hdr) ((hdr)->_len) 43 //获取数据报标识 44 #define IPH_ID(hdr) ((hdr)->_id) 45 //获取分片标志位+偏移量 46 #define IPH_OFFSET(hdr) ((hdr)->_offset) 47 //获取偏移量大小(字节) 48 #define IPH_OFFSET_BYTES(hdr) 49 ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U)) 50 //获取生存时间 51 #define IPH_TTL(hdr) ((hdr)->_ttl) 52 //获取上层协议 53 #define IPH_PROTO(hdr) ((hdr)->_proto) 54 //获取校验和 55 #define IPH_CHKSUM(hdr) ((hdr)->_chksum) 56 57 58 /* 用于填写 IP 数据报首部的宏*/ 59 60 //设置版本号跟首部长度 61 #define IPH_VHL_SET(hdr, v, hl) 62 (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) 63 //设置服务类型 64 #define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) 65 //设置数据报总长度 66 #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) 67 //设置标识 68 #define IPH_ID_SET(hdr, id) (hdr)->_id = (id) 69 //设置分片标志与偏移量 70 #define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) 71 //设置生存时间 72 #define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) 73 //设置上层协议 74 #define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) 75 //设置校验和 76 #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
(1)分片处理的原因
IP数据报被传送至链路层,链路层将IP数据报封装成链路层帧,网卡硬件将链路层帧发送至目标主机。一个链路层帧能携带的最大数据量称为最大传送单元(MTU),不同网卡硬件的MTU可能不一样。当IP数据报的长度超过MTU,则需对其进行分片处理后,再发送。
(2)分片处理的原理
IP数据报的分片处理,是将IP数据报中的数据区域切割为若干个较小的IP数据报,并封装成单独的链路层帧后进行发送。
(3)分片处理示例
主机发送一个4000Byte的IP数据报,链路层MTU = 1500Byte,需要对原始IP数据报进行分片处理。
原始IP数据报(4000Byte)= IP首部(20Byte)+ 数据区域(3980Byte),对数据区域进行切割,并填写每个分片IP首部的“标志”、“分片偏移量”字段。
第一个分片:“标志”字段BIT(2) = 1,分片偏移量为0,分片数据报长度(1500Byte)= IP首部(20Byte)+ 数据区域(1480Byte);
第二个分片:“标志”字段BIT(2) = 1,分片偏移量为185(1480/8),分片数据报长度(1500Byte)= IP首部(20Byte)+ 数据区域(1480Byte);
第三个分片:“标志”字段BIT(2) = 0,分片偏移量为370(185+185),分片数据报长度(1040Byte)= IP首部(20Byte)+ 数据区域(1020Byte)。
(4)分片处理的源码
分片处理的源码位于“lwip_2_1_2/src/core/ipv4/ip4_frag.c”,调用“ip4_frag()”函数对IP数据报进行分片处理并发送至目标主机。
IP数据报的发送与接收,源码位于:lwip_2_1_2/src/core/ipv4/ip4.c
1. 野火《LwIP应用开发实战指南》。
原文:https://www.cnblogs.com/linfeng-learning/p/12456138.html