IP 协议(Internet Protocol),又称之为网际协议,属于网络层。IP协议以IP地址作为唯一识别码,负责将数据从源主机发送到目标主机。

IP 协议是一种无连接的不可靠数据报交付协议,协议本身不提供任何的错误检查与恢复机制。 

1.1 IP地址

在互联网中,每一个主机都有一个唯一的IP地址作为身份识别标志。

(1)分类编址

IP地址可分为五类:A类、B类、C类、D类、E类,其组成如下图。

LWIP协议栈:IP协议

   各类IP地址的特点,如下图。

LWIP协议栈: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地址不明确的情况。

 1.2 局域网、广域网、互联网

局域网(Local Area Network,缩写为 LAN),又称内网,覆盖局部区域的计算机网络。

广域网((Wide Area Network,缩写为 WAN),又称外网、公网,连接不同区域的计算机网络进行通信。

互联网,由无数个局域网,通过广域网线路汇聚互联形成。

局域网、广域网、互联网三者间关系如下图所示。

LWIP协议栈:IP协议

  • 无线路由器为手机、电脑分配局域网IP(LAN-IP)。路由器的IP地址,由运营商分配(运营商的局部IP地址),该地址将被转换为广域网IP地址(WAN-IP)。广域网IP地址(WAN-IP)也需要转换为互联网公共IP地址(Global-IP),才能进入互联网。
  • 网络通信的IP地址转换过程:LAN-IP <—> WAN-IP <—> Global-IP。

1.3 网络地址转换

NAT(Network Address Translation),网络地址转换,其功能是实现局域网IP地址与广域网IP地址之间的转换,即完成LAN-IP <—> WAN-IP之间的转换。

示例:

LWIP协议栈:IP协议

  • 具有NAT功能的路由器拥有两个IP地址,一个内部地址,用于进行局域网内部的通信;一个外部地址,用于与广域网进行通信,由运营商分配。
  • 具有 NAT 功能的路由器会在其内部维护一个 NAT 转换表。当路由器收到局域网的IP数据报时,路由器会为该数据报分配一个它内部的 NAT 端口(譬如:port 6666),局域网主机IP地址(192.168.0.181:5555)与广域网IP地址(223.166.166.66:6666)形成一个映射。从而,局域网主机能够实现与广域网进行通信。
  • NAT转换中,路由器会每个连接的局域网主机分配唯一的NAT端口号,并回收失效端口号。

2. IP报文

2.1 IP报文格式

LWIP协议栈:IP协议

  •  版本:IP协议的版本号。IPv4的版本号为4,IPv6的版本号为6。
  • 首部长度:记录IP首部所占的空间,单位“字”。占4bit,因此IP首部的最大长度为15*4=60Byte。
  • 服务类型(TOS):用于区分不同的IP数据包。譬如,区分一些特别要求低时延、高吞吐量或可靠性的数据包;从而便于路由器为此类IP数据包提供更合理的路径。
  • 数据报长度:IP报文的总长度,IP首部+数据区域的长度,单位“字节”。该长度一般不超过以太网数据帧的最大长度(MTU_MAX=1500Byte),若超过,则需进行分片发送。若该长度小于MTU_MIN(46Byte),则需填充至MTU_MIN后再发送。
  • 标识:用于判断各个IP数据报分片是否属于同一个数据报。每发送一个IP数据报,该字段的值+1;属于同一个IP数据报的分片,该字段的值相等。
  • 标志:占3bit。BIT(0)保留未用;BIT(1)为1表示该数据报允许进行分片处理,为0表示禁止分片处理(此时,若数据报长度超过MTU_MAX,则丢弃该数据报);BIT(2)为0表示该分片是整个数据报的最后一个分片,反之则不是。
  • 分片偏移量:表示当前分片所携带的数据在整个IP数据报中的偏移量,以8Byte为单位。
  • 生存时间(TTL):每当IP数据报被一个路由器处理后,该字段的值减1;当减为0时,丢弃该数据报。从而确保IP数据报不会永远在网络中循环(譬如由于长时间的路由选择环路)。
  • 上层协议:表示IP数据报的数据部分应该交由哪个传输协议(TCP、UDP、)处理。
  • 首部校验和:IP数据报首部的校验和,用于帮助路由器检测收到的IP数据报的首部是否正确。
  • 源IP地址:源主机的IP地址。
  • 目标IP地址:目标主机的IP地址。
  • 选择:该字段不是必须组成部分。LWIP协议栈只识别选项字段,但是不会处理它的内容。
  • 数据区域:IP数据报所携带额数据。

P.S.:IPv4和IPv6的报文格式不同,此处记录的为IPv4报文格式。

2.2 IP报文数据结构定义

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)
IP报文数据结构定义

相关文章: