(急)IP协议源代码(C++)中的转发函数谁能帮忙解释一下?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(急)IP协议源代码(C++)中的转发函数谁能帮忙解释一下?相关的知识,希望对你有一定的参考价值。

头文件和转发函数(ip_forward)如下:C++我学了,但看不懂那函数,其中的变量代表什么,那些if语句的条件,还有些乱七八糟的函数是什么意思也看不懂,哪位高手能帮我解释一下代码? 越详细越好.. 小弟感激不尽.
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif
/* ip_forward:
*
* Forwards an IP packet. It finds an appropriate route for the
* packet, decrements the TTL value of the packet, adjusts the
* checksum and outputs the packet on the appropriate interface.
*/
/*-----------------------------------------------------------------------------------*/
static void
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)

static struct netif *netif;

PERF_START;

if((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL)

DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
iphdr->dest.addr));

return;


/* Don't forward packets onto the same network interface on which
they arrived. */
if(netif == inp)
DEBUGF(IP_DEBUG, ("ip_forward: not forward packets back on incoming interface.\n"));

return;


/* Decrement TTL and send ICMP if ttl == 0. */
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
if(IPH_TTL(iphdr) == 0)
/* Don't send ICMP messages in response to ICMP messages */
if(IPH_PROTO(iphdr) != IP_PROTO_ICMP)
icmp_time_exceeded(p, ICMP_TE_TTL);

return;


/* Incremental update of the IP checksum. */
if(IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100))
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
else
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));


DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n",
iphdr->dest.addr));

#ifdef IP_STATS
++stats.ip.fw;
++stats.ip.xmit;
#endif /* IP_STATS */

PERF_STOP("ip_forward");

netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));

#endif

PERF_START 转发开始,初始化。

ip_forward() 转发函数, 转发一个数据包。

ip_route() 找通向目的地的路线。
(struct ip_addr *)&(iphdr->dest 目的地转成ip_addr结构。如果 找到路线,送返 结构 netif,否则 送返 NULL。
if((ip_route ...NULL) 如果送返 NULL,也就是没找到路线,则做 ...

找到路线, 但是 if(netif == inp) ,表示同一个数据包,已到达,不必转发。

IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); 如果ttl == 0,为防止数据包不断在 IP 互联网络上永不终止地循环,减小 数据包 生存时间TTL 1,icmp..是否执行封包回显应答。

IPH_CHKSUM_SET 更新 IP checksum 检查,根据条件决定是否+1。

DEBUGF -- 查错时输出的信息

#ifdef IP_STATS ... #endif
如果定义了IP_STATS (IP 开始) 则...

PERF_STOP() 终止 转发
参考技术A 经过楼上loonie的解释,这下你明白了嘛?

不明白也没有关系,先找本《计算机网络》把IP协议的相关知识了解下

另外,可以到网上下载这个协议的具体规范文档,把协议了解清楚了再看代码就不难了

IP协议详解(IP协议格式IP地址管理路由转发)

目录


1. IP协议格式

如图:

  • 4位版本:标识当前是ipv4协议。

  • 4位首部长度:和TCP一样,计算出来的是数值,需要乘以4,才是具体的首部长度。

    首部长度 = 4位首部长度(DEC) * 4 ,单位字节

  • 8位服务类型(TOS):前三位代表优先级,但是弃用了,接下来四位依次是:最小延时(ssh)、最大吞吐量(ftp)、最高可靠性、最小成本。剩下一位是保留位。

  • 16位总长度:能够表示ip数据包的最大长度为216,单位为字节,包含了ip头部和ip数据包的有效载荷。

  • 16标识:标识哪些ip数据报是同一条数据。

  • 3位标志:

    第一位表示保留位
    第二位表示禁止分片
    第三位表示分片是否结束

    1:表示后面还有分片
    0:表示后面没有分片

  • 13位片偏移:表示在同一条数据当中的哪一个位置。

  • 8位生存时间(TTL):经历路由器的最大跳数,换句话说,路由器能够转发该条数据的最大次数。

    每经历一个路由器转发,TTL减1。
    TTL > 0:表示路由器还可以继续转发。
    TTL == 0:路由器就直接将这条ip数据丢弃了。
    ip数据报的TTL默认一般是64。

  • 8位协议:记录上层协议该条数据需要递交给传输层的哪一个协议。

  • 16位首部校验和:检验数据在传输过程中是否失真。

  • 32位源ip地址、32位目的ip地址

    ① 链路中的结点都会对ip数据报进行分用,获得目的ip地址之后,进行路由传输。
    ② 一般情况下,在网络传输过程中是不会篡改ip地址的。
    ③ 当ip是私网ip地址的时候,会被NAT服务器进行修改。


ip协议用来表示一条数据所使用的是:(一条ip数据报)

16位总长度 + 16位标识 + 3位标志 + 13位片偏移

16位总长度能够标识的数据最大为65536Byte,如果传输层递交给网络层ip协议的数据超过65536Byte,那应该如何做?

答案是在网络层的ip协议进行分片传输。

那么,问题来了,TCP需要ip协议进行分片吗?

解答:不需要进行分片,因为TCP协议在传输数据的时候,严格按照MSS进行传输,而MSS一定是小于MTU的,而一般网卡的MTU都是1500字节,换句话说,TCP在每次传输数据的时候都是不会超过1500字节的。因此,MSS是远远小于65536字节的,因此也就不会触发ip协议进行分片传输。

UDP需要ip协议进行分片吗?

解答:有可能需要进行分片,因为UDP协议是没有类似于MSS存在的,因此,UDP的数据的最大长度是65536字节,网络层递交给数据链路层大小必须小于MTU的,因此,一旦UDP递交给网络层ip协议的数据加上ip协议报头之后,总长度大于了当前主机的MTU大小时,就会需要进行分片传输。
注:因为UDP协议是不可靠的,在ip数据报转发的时候,都有自己的路由转发路径,可能会造成丢失。


2. IP地址管理

ip地址的分为两个部分,网络号和主机号

  • 网络号:保证互相连接的两个网段具有不同的标识。
  • 主机号:同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号。

换句话来说,ip地址 = 网络号 + 主机号

  • 网络号:在网络中标识了一堆的网络。
  • 主机号:在同一网络号中标识不同的主机。

ipv4版本的ip地址:本质是uint32_t,范围是[0 , 232 - 1]。

2.1 早期地址管理方式

早期ip地址的划分方式:A类、B类、C类、D类、E类。

A类:

B类:

C类:

需要注意的是:

  • 在一个网段中都会有一个网络号的和广播号,即 192.0.0.0 ~ 192.0.0.255
  • 网络号:主机号全为0的ip地址,就为该网段中的网络号
  • 广播号:主机号中全为1的ip地址,就为该网段中的广播号
  • 127.0.0.1 :本地回环网卡地址(通常用来测试自己机器的网络连通性)
  • 0.0.0.0:代表本地所有的网卡地址

2.2 CIDR方式

引入CIDR方式,是为了更加精细的划分网络当中的主机数量而诞生的,并且CIDR方式也引入了子网掩码。

子网掩码: 本质也是uint32_t的整数,但是这个整数从最高的比特位到某一个低位的比特位之间一定是全1的,且中间是没有0的。

计算当前网络的网络号:

网络号 = ip 地址 & 子网掩码

注意:这已经和之前的ABC类地址没有关系了,这是新的划分方式。

如何得到当前子网中的IP地址使用多少个比特位作为主机号?

解答:子网掩码取反等于当前最大的主机号

取反之后,有多少比特位为1,则表示当前子网当中的ip地址使用了多少个比特位当作是主机号。

例题:

ip:172.16.99.129,子网掩码:255.255.255.0
如果想要将该子网平均划分为4个子网,则对应的子网掩码是什么?

缓解IPV4地址枯竭的一些办法:

  • DHCP协议,谁上网给谁分配ip(本质上也是路由器进行分配的)
  • 在ip地址当中划分出三段,作为私网的ip地址

私网ip地址不具有访问互联网的效力
10 . * . * . *:10.0.0.0 ~ 10.255.255.255
172.16. * . * ~ 172.31. * . *:172.16.0.0 ~ 172.31.255.255
192.168. * . *:192.168.0.0 ~ 192.168.255.255

虽说当前这些ip地址不能直接访问互联网,但是可以在不同的子网当中进行复用。

3. 网络层的路由转发

IP协议相当于OSI参考模型中的第3层——网络层。

网络层的主要作用是“实现终端节点之间的通信”。这种终端节点之间的通信也叫“点对点(end-to-end)通信”。

网络层的下一层——数据链路层的主要作用是在互连同一种数据链路的节点之间进行包传递。而一旦跨越多种数据链路,就需要借助网络层。网络层可以跨越不同的数据链路,即使是在不同的数据链路上也能实现两端节点之间的数据包传输。

首先我们要知道路由器分为WAN和LAN口。

WAN:连接上级路由器
LAN:用来组装当前路由器的子网


① 从运营商机房拉出的网线插在了家用路由器的WAN口上。
② 个人设备是插在家用路由器的LAN口上

其次,我们需要知道网络数据的五元组信息。

源ip、目的ip、源端口、目的端口、协议

在路由设备中都会有一个路由表,路由表记录了当前的路由项。

可以使用命令:route -n

那么路由器是如何进行网络转发的呢?

  • 首先用网络数据中的目的ip和路由项当中的子网掩码进行按位与操作(需要注意的是,该目的ip先和非网关的路由项进行操作,最后再和网关路由项进行操作)。
  • 其次将按位与操作的结果和路由项的Destination进行对比

① 如果说没有对比上,则代表该条数据不是往该子网当中进行转发。
② 如果说对比上了,则代表该条数据是往该子网当中的某一个主机进行转发的。

需要注意的是:

① 如果该条数据的目的ip是当前子网的某一主机,则不需要WAN的转发,直接走路由器的LAN口
② 如果该条数据的目的ip是互联网当中的某一个主机,则需要经过WAN口的转发,传输到上级路由器再进行路由。
③ 路由表也是需要更新的。

路由的过程, 就是这样一跳一跳(Hop by Hop) “问路” 的过程。所谓 “一跳” 就是数据链路层中的一个区间. 具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间.


IP数据包的传输过程也和问路一样.

  • 当IP数据包, 到达路由器时, 路由器会先查看目的IP;
  • 路由器决定这个数据包是能直接发送给目标主机, 还是需要发送给下一个路由器;
  • 依次反复, 一直到达目标IP地址

以上是关于(急)IP协议源代码(C++)中的转发函数谁能帮忙解释一下?的主要内容,如果未能解决你的问题,请参考以下文章

概说《TCP/IP详解 卷2》第8章 IP:网际协议

(急~急~急)请帮忙,谢谢了

用matlabGUI界面读取图片,滑动滚动条来调节图像亮度,用imadd函数,代码一直出错,急,求高手帮忙

lua 与 c++或者c 交互的底层原理谁能解释一下?最最底层的,为啥它们调用C或者C++的函数?

急急急!谁能给我解释下String IPs=request.getRemoteAddr();啥意思啊

谁能帮忙举个例子,用DELPHI写个简单例子,调用PING命令并且取回PING结果显示MSG BOX里,要通过管道技术取