《Linux高性能服务器编程》学习总结(二)——IP协议详解

第二章      IP协议详解

  IP协议是TCP/IP协议族中的核心协议,也是socket网络编程的基础之一。IP协议的特点是为上层提供无状态、无连接、不可靠的服务。

  无状态是指IP通信双方不同步传输数据的状态信息,通俗一些说就是双方发送的IP数据报是相互独立的,没有任何上下文关系。这样的特性缺点在于无法处理重复和乱序的IP数据报,举个例子,假设由于网络原因或者IP选路的原因导致第N个数据报比第N+1个数据报晚到达目的主机或同一个IP数据报经过不同的路径多次到达目的端,此时接收端的IP模块无法检测到乱序和重复,当向上层协议交付数据的时候,就会导致失序。当然,无状态的优点也很明显,简单而高效,我们没有必要像TCP协议一样为了维持连接而占用一部分内核资源,通信双方也不用在IP层交换状态信息。

  无连接是指通信双方都不长久维持对方的任何信息,所以上层协议在发送数据的时候都必须指明对方的IP地址。

  不可靠是指IP协议不能保证对方收到IP数据包,只能保证尽最大努力交付,而一旦发送方检测到发送失败,只会通知上层,并不会重传,所以对于数据的可靠传输需要由上层协议完成。

  在IPv4的首部中,值得注意的几个要点有,首先4位首部长度是标识该IP首部有多少个32bit,也就是有多少个4字节,所以,IP首部的最大长度为(24-1)*4=60字节,而16位总长度是以字节数为单位的,所以IP数据报的最大长度为(216-1)=65535字节,但是由于路径MTU的存在,一般实际传输中长度远没有达到这个最大值。下面的三位标志中第一位保留,第二位是DF位,表示禁止分片,若此位置一,则IP模块将强制不分片,第三位是MF位,表示更多分片,除了数据报的最后一个分片以外其余分片都应将此为置一。接下来的13位片偏移是以8字节为单位的,换句话说就是实际的片偏移是这个位的值左移三位,所以,除了最后一个分片外,其余分片长度都应该是8的整数倍。

  关于IP分片,若IP数据报的长度大于了MTU,则他将被分片传输,而分片可能发生在发送端,可能发生在传输过程中,数据报也可能被多次分片,但是只会在接收端的IP模块被重新组装。下面我们用一个例子来看一下IP分片的过程和组装。

  以太网的MTU是1500,所以除去IP首部,数据部分最大能传输1480字节。假设我们现在有一个1481字节的ICMP报文,其中包含8字节的ICMP首部和1473字节的数据部分,则发送端IP模块会讲包含ICMP首部的前1480字节截取,加上IP首部作为第一个分片,将MF置1,最后剩余的1字节加上MF置0的IP首部发送到接收端。所以我们看到,对于IP模块而言,上层的协议首部和数据部分是一样的,在本层都是数据部分。而当两个数据包传送到接收端时,IP模块依次剥离两报文的IP首部将其组装起来。但是前面我们提到过,IP协议是无状态的,也就是两个IP报文是没有上下文联系的,如果第二个报文段先一步到达接收端,那么接收端还能正确将其组装吗?答案是肯定的,因为前面我们讲到了IP首部有片偏移字段,根据这个字段,IP模块就能将IP分片准确地放在应该放在的地方了。

  下一个重要的问题就是,IP协议是如何选路的呢?为了研究这个问题,我们就要先理解IP模块的工作流程。

  IP模块的工作流程看起来很复杂,但是其实很简单,我们从右向左分析。当主机收到一个数据报后,先对数据报头部进行CRC校验,确认后开始分析头部信息;如果该数据报设置了源站选路选项则调用数据报转发子模块进行处理;否则继续看目的IP地址是不是本机的IP地址或者广播地址,即这个数据报是不是发送给自己的,如果是,则向上层协议交付数据,若不是,继续调用数据报转发子模块;当数据报转发子模块收到一个报文时,先检测本机系统是否允许转发,如果不允许则丢弃之,若允许则将对其进行一些操作后交给IP数据报输出子模块。

  而我们略过的转发过程、选择下一跳路由以及ICMP重定向等就是IP选路的核心。IP模块实现数据报路由的核心数据结构是路由表,这个表按照数据报的目标IP地址进行分类,同一类型的IP数据报会发给相同的下一跳,而路由表对IP地址进行分类,就是IP的路由机制,共分为三个步骤:1)查找路由表中和数据报的目标IP地址完全匹配的主机地址,如果找到就使用该路由表项,否则转向步骤2。2)查找路由表中和数据报的目的IP地址具有相同网络ID的网络IP地址,即是同一网段的IP地址,如果找到则使用该路由表项,否则转向步骤3。3)选择默认路由,通常意味着下一跳路由是网关。

  读到这里我们会想,那么路由表又是如何生成的呢,主机又是如何知道发往哪些IP地址的数据包应该转发给谁呢?路由表的更新有两种方式,第一种是手工静态更新,但是一般应用很少,只在本机实验时会用到,第二种就是通过BGP、RIP、OSPF协议等进行更新路由表。

  数据转发子模块在收到需要转发的数据报并且本机允许转发的情况下,将执行如下操作:1)检查数据报头的TTL,如果TTL为0则将之抛弃。2)查看数据报头部的严格源站选路选项,若已经被设置则检查是否是本机的某个IP地址,如果不是则发送一个ICMP源站选路失败报文给发送端。3)如果有必要则向源端发送ICMP重定向报文。4)将TTL减一。5)处理IP头部选项。6)如果有必要则进行IP分片。

  前面提到了ICMP重定向报文,这个是做什么的呢?其实就是主机告诉源端,这个数据报从我这里走绕远了,并且告诉他应该怎么走。举个例子,在一个网段上有主机A和主机B,网关是路由器C,连接着外网,我们把A的网关地址改成B的IP地址,并将B的转发功能打开,这时用A向外网发送一个数据报,数据报先发给默认网关即主机B,但是主机B发现它自己接收到这个包的端口和它即将转发的端口是同一个,而且源地址主机A和他的下一跳路由器C是同一网段内,他就会告诉A,你可以直接走C,不经过我,这样A就可以利用ICMP重定向来对自己的路由表进行更新。

原文地址:https://www.cnblogs.com/Torrance/p/8387740.html

时间: 2024-10-05 05:05:48

《Linux高性能服务器编程》学习总结(二)——IP协议详解的相关文章

Linux高性能服务器编程——多进程编程

多进程编程 多进程编程包括如下内容: 复制进程影映像的fork系统调用和替换进程映像的exec系列系统调用. 僵尸进程以及如何避免僵尸进程 进程间通信(Inter-Process Communication,IPC)最简单的方式:管道 3种进程间通信方式:信号量,消息队列和共享内存 fork系统调用 #include<unistd.h> pid_tfork(void); 该函数的每次都用都返回两次,在父进程中返回的是子进程的PID,在子进程中返回的是0.该返回值是后续代码判断当前进程是父进程还

Linux高性能服务器编程——I/O复用

 IO复用 I/O复用使得程序能同时监听多个文件描述符,通常网络程序在下列情况下需要使用I/O复用技术: 客户端程序要同时处理多个socket 客户端程序要同时处理用户输入和网络连接 TCP服务器要同时处理监听socket和连接socket,这是I/O复用使用最多的场合 服务器要同时处理TCP请求和UDP请求.比如本章将要讨论的会社服务器 服务器要同时监听多个端口,或者处理多种服务. I/O复用虽然能同时监听多个文件描述符,但它本身是阻塞的.并且当多个文件描述符同时就绪时,如果不采用额外措施

linux高性能服务器编程

<Linux高性能服务器编程>:当当网.亚马逊 目录: 第一章:tcp/ip协议族 第二章:ip协议族 第三章:tcp协议详解 第四章:tcp/ip通信案例:访问Internet 第五章:linux网络编程基础API 第六章:高级IO函数 第七章:linux服务器程序规范 第八章:高性能服务器框架 第九章:IO复用 第十章:信号 第十一章:定时器 第十二章:高性能IO框架库libevent 第十三章:多进程编程 第十四章:多线程编程 第十五章:进程池和线程池 第十六章:服务器调制.调试和测试

Linux高性能服务器编程——定时器

 定时器 服务器程序通常管理着众多定时事件,因此有效组织这些定时事件,使之能在预期的时间点被触发且不影响服务器的主要逻辑,对于服务器的性能有着至关重要的影响.位置我们要将每个定时事件封装成定时器,并使用某种容器类型的数据结构,比如链表.排序链表和时间轮将所有定时器串联起来,以实现对定时事件的统一管理. Linux提供三种定时方法: 1.socket选项SO_RECVTIMEO和SO_SNDTIMEO. 2.SIGALRM信号 3.I/O复用系统调用的超时参数 socket选项SO_RCVTI

Linux 高性能服务器编程——高级I/O函数

重定向dup和dup2函数 [cpp] view plaincopyprint? #include <unistd.h> int dup(int file_descriptor); int dup2(int file_descriptor_one, int file_descriptor_two); dup创建一个新的文件描述符, 此描述符和原有的file_descriptor指向相同的文件.管道或者网络连接. dup返回的文件描述符总是取系统当前可用的最小整数值. dup2函数通过使用参数f

Linux高性能服务器编程——信号及应用

 信号 信号是由用户.系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常.Linux信号可由如下条件产生: 对于前台进程,用户可以通过输入特殊的终端字符来给它发送信号.比如输入Ctrl+C通常会给进程发送一个终端信号. 2.系统异常 系统状态变化 运行kill命令或调用kill函数 Linux信号概述 发送信号 Linux下,一个进程给其他进程发送信号的API是kill函数.其定义如下: #include <sys/types.h> #include <sign

Linux高性能服务器编程——进程池和线程池

进程池和线程池 池的概念 由于服务器的硬件资源"充裕",那么提高服务器性能的一个很直接的方法就是以空间换时间,即"浪费"服务器的硬件资源,以换取其运行效率.这就是池的概念.池是一组资源的集合,这组资源在服务器启动之初就完全被创建并初始化,这称为静态资源分配.当服务器进入正是运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配.很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因为分配系统资源的系统调用都是很耗时的.当

Linux高性能服务器编程——Linux网络基础API及应用

 Linux网络编程基础API 详细介绍了socket地址意义极其API,在介绍数据读写API部分引入一个有关带外数据发送和接收的程序,最后还介绍了其他一些辅助API. socket地址API 主机字节序和网络字节序 字节序分为大端字节序和小端字节序.小端字节序又被称为主机字节序,大端字节序被称为网络字节序.大端字节序是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处.小端字节序则相反. Linux提供如下四个函数完成主机字节序与网络字节序之间的转换: #include

Linux高性能服务器编程——系统检测工具

系统检测工具 tcpdump tcpdump是一款经典的转包工具,tcpdump给使用者提供了大量的选项,泳衣过滤数据报或者定制输出格式. lsof lsof是一个列出当前系统打开的文件描述符的工具.通过它我们可以了解感兴趣的进程打开了哪些文件描述符,或者我们感兴趣的文件描述符被哪些进程打卡了. nc nc命令主要被用来快速构建网络连接.我们可以让它以服务器方式运行,监听某个端口并接收客户连接,因此它可用来调试客户端程序.我们也可以使之以客户端方式运行,向服务器发起连接并收发数据,因此它可以用来