【Network】IP 协议(网际协议)

Posted by 西维蜀黍 on 2019-05-08, Last Modified on 2021-09-21

IP 协议(网际协议)

IP协议是TCP/IP协议的核心,所有的TCP,UDP,IMCP,IGCP的数据都以IP数据格式传输。

要注意的是,IP不是可靠的协议,这是说,IP协议没有提供一种数据未传达以后的处理机制--这被认为是上层协议(TCP或UDP)来负责的事情。所以这也就出现了TCP是一个可靠的协议,而UDP就没有那么可靠的区别。

IP Datagram Format

IPv4

IPv4 Datagram分为首部(Header)数据两部分。IPv4 Header由**固定部分(Basic)选项部分(Options)**组成,其中固定部分的大小为20 bytes。IPv4 Header最大为60 bytes。

IP版本:现在的IP版本号是4,所以也称作IPv4。现在还有IPv6,而且运用也越来越广泛了。

TTL(Time-to-Live):这个字段规定该数据包在穿过多少个路由之后会被抛弃。

这里就体现出来IP协议包的不可靠性,它不保证数据被送达。某个IP数据包每穿过一个路由器,该数据包的TTL数值就会减少1,当该数据包的TTL成为零,它就会被自动抛弃。这个字段的最大值也就是255,也就是说一个协议包也穿行过路由器255次后就会被抛弃了,根据系统的不同,这个数字也不一样,一般是32或者是64,Tracerouter这个工具就是用这个原理工作的,tranceroute的-m选项要求最大值是255,也就是因为这个TTL在IP协议里面只有8bit。

ToS(Type of Service):DS Field(Differentiated Services Field) + ECN(Explicit Congestion Notification, 显式拥塞通知)

IPv6

与IPv4 Header不同,IPv6 Header具有固定的大小(40 bytes),并且没有选项部分。但是IPv6 Header可以有扩展首部(extension headers),其作用与Options类似。Next Header字段用于指示extension headers。

IP路由选择

当一个IP数据包准备好了的时候,IP数据包(或者说是路由器)是如何将数据包送到目的地的呢?它是怎么选择一个合适的路径来"送货"的呢?

最特殊的情况是目的主机和主机直连,那么主机根本不用寻找路由,直接把数据传递过去就可以了。至于是怎么直接传递的,这就要靠ARP协议了。

稍微一般一点的情况是,主机通过若干个路由器(router)和目的主机连接。那么路由器就要通过IP包的信息来为IP包寻找到一个合适的目标来进行传递,比如合适的主机,或者合适的路由。路由器或者主机将会用如下的方式来处理某一个IP数据包:

  • 如果IP数据包的TTL(生命周期)已到,则该IP数据包就被抛弃。
  • 搜索路由表,优先搜索匹配主机,如果能找到和IP地址完全一致的目标主机,则将该包发向目标主机
  • 搜索路由表,如果匹配主机失败,则匹配同子网的路由器,这需要“子网掩码(1.3.)”的协助。如果找到路由器,则将该包发向路由器。
  • 搜索路由表,如果匹配同子网路由器失败,则匹配同网号路由器,如果找到路由器,则将该包发向路由器。
  • 搜索路由表,如果以上都失败了,就搜索默认路由,如果默认路由存在,则发包
  • 如果都失败了,就丢掉这个包

这再一次证明了,IP包是不可靠的。因为它不保证送达。

IP分片

物理网络层一般要限制每次发送数据帧的最大长度。任何时候IP层接收到一份要发送的IP数据报时,它要判断向本地哪个接口发送数据(选路),并查询该接口获得其MTU。IP把MTU与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上。

把一份IP数据报分片以后,只有到达目的地才进行重新组装(这里的重新组装与其他网络协议不同,它们要求在下一站就进行进行重新组装,而不是在最终的目的地)。重新组装由目的端的IP层来完成,其目的是使分片和重新组装过程对运输层(TCP和UDP)是透明的,除了某些可能的越级操作外。已经分片过的数据报有可能会再次进行分片(可能不止一次)。IP首部中包含的数据为分片和重新组装提供了足够的信息。

回忆IP首部,下面这些字段用于分片过程。对于发送端发送的每份IP数据报来说,其标识字段都包含一个唯一值。该值在数据报分片时被复制到每个片中(我们现在已经看到这个字段的用途)。标志字段用其中一个比特来表示“更多的片”。除了最后一片外,其他每个组成数据报的片都要把该比特置1。片偏移字段指的是该片偏移原始数据报开始处的位置。另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。

当IP数据报被分片后,每一片都成为一个分组,具有自己的IP首部,并在选择路由时与其他分组独立。这样,当数据报的这些片到达目的端时有可能会失序,但是在IP首部中有足够的信息让接收端能正确组装这些数据报片。

尽管IP分片过程看起来是透明的,但有一点让人不想使用它:即使只丢失一片数据也要重传整个数据报。为什么会发生这种情况呢?因为IP层本身没有超时重传的机制——由更高层来负责超时和重传(TCP有超时和重传机制,但UDP没有。一些UDP应用程序本身也执行超时和重传)。当来自TCP报文段的某一片丢失后,TCP在超时后会重发整个TCP报文段,该报文段对应于一份IP数据报。没有办法只重传数据报中的一个数据报片。事实上,如果对数据报分片的是中间路由器,而不是起始端系统,那么起始端系统就无法知道数据报是如何被分片的。就这个原因,经常要避免分片。

使用UDP很容易导致IP分片(在后面我们将看到,TCP试图避免分片,但对于应用程序来说几乎不可能强迫TCP发送一个需要进行分片的长报文段)。我们可以用sock程序来增加数据报的长度,直到分片发生。在一个以太网上,数据帧的最大长度是1500字节,其中1472字节留给数据,假定IP首部为20字节,UDP首部为8字节。我们分别以数据长度为1471,1472,1473和1474字节运行sock程序。最后两次应该发生分片:

Reference