LWIP开源协议栈

LWIP开源协议栈

只需读懂这个文章就够了 LWIP应用开发实战指南
简介
  • lwIP是软件,那么怎么让硬件与软件无缝连接起来呢? 而且,网卡又有多种多样,怎么能让LwIP使用同样的软件能兼容不同的硬件呢? 原来LwIP使用一个数据结构——netif来描述一个网卡,但是由于网卡是直接与硬件打交道的, 硬件不同则处理基本是不同的,所以必须由用户提供最底层接口函数,LwIP提供统一的接口, 但是底层的实现需要用户自己去完成,比如网卡的初始化,网卡的收发数据,当LwIP底层得到了网络的数据之后, 才会传入内核中去处理;同理,LwIP内核需要发送一个数据包的时候,也需要调用网卡的发送函数, 这样子才能把数据从硬件接口到软件内核无缝连接起来。LwIP中的 ethernetif.c文件即为底层接口的驱动的模版,用户为自己的网络设备实现驱动时应参照此模块做修改。ethernetif.c文件中的函数通常为与硬件打交道的底层函数,当有数据需要通过网卡接收或者发送数据的时候就会被调用,经过LwIP协议栈内部进行处理后,从应用层就能得到数据或者可以发送数据。
  • 在单网卡中,这个netif结构体只有一个,可能还有人会问,那么一个设备中有多个网卡怎么办,很简单,LwIP会将每个用netif描述的网卡连接成一个链表(单向链表),该链表就记录每个网卡的netif。屏蔽硬件接口的差异,完成了对不同网卡的抽象,因此了解netif结构体是移植LwIP的关键。

low_level_init()为网卡初始化函数,它主要完成网卡的复位及参数初始化,根据实际的网卡属性进行配置netif中与网卡相关的字段,例如网卡的MAC地址、长度,最大发送单元等。

low_level_output()函数为网卡的发送函数,它主要将内核的数据包发送出去,数据包采用pbuf数据结构进行描述,该数据结构是一个比较复杂的数据结构,后续我们会详细讲解。

low_level_input()函数为网卡的数据接收函数,该函数会接收一个数据包,为了内核易于对数据包的管理,该函数必须将接收的数据封装成pbuf的形式。

除此之外,还有两个函数也与网卡与关系,分别是:

 err_t ethernetif_init(struct netif *netif);
 void ethernetif_input(void *pParams);

LwIP让协议栈内核与操作系统相互隔离,协议栈仅仅作为操作系统的一个独立线程存在,用户程序能驻留在协议栈内部,协议栈通过回调函数实现用户与协议栈之间的数据交互;也可以让用户程序单独实现一个线程,与协议栈使用系统的信号量和邮箱等IPC通信机制联系起来,进行数据的交互。当使用第一种通过回调函数进行交互情况的时候,也就是我们所说的RAW API编程,而使用第二种通过操作系统IPC通信机制的时候,就是另外两种API编程,即NETCONN API和Socket API。当然这样子既有优点也有缺点,优点就是能在任何的操作系统中移植,缺点就是受到操作系统的影响,因为即使LwIP作为一个独立的线程,也是需要借助操作系统进行调度的,因此,协议栈的响应的实时性会有一定影响,并且建议设置LwIP线程的优先级为最高优先级。

LWIP主要模块流程图
网卡接收数据的流程

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

移植相关
  • LWIP支持无操作系统模式(while循环处理)和操作系统模式
    1. 需要将网卡数据转化到lwip, 以及从lwip转化到网卡数据, 这一部分一般无需移植者处理, 直接从网上获取资源
    2. 配置LwIP , lwipopts.h
源码剖析
  • altcp.c、altcp_alloc.c、altcp_tcp.c等文件是应用程序分层TCP连接API,从TCPIP线程使用,是一个抽象层,可以模拟应用程序的tcp回调API,同时防止直接链接,这样,应用程序可以使用其他应用程序层协议在TCP之上而不知道细节(例如TLS,代理连接),此类接口我们并没有怎么使用,或者如果选择使用安全的加密传输的话,可以配合mbed TLS使用。- -
  • pbuf.c文件实现了LwIP对网络数据包的各种操作。网络数据包在LwIP内核中以pbuf结构体的形式存在,这提高了LwIP内核对数据包处理效率,以及提高了数据包在各层之间递交的效率。pbuf结构体也是我们使用RAW/Callback API进行网络应用程序开发的关键,后续我们会详细讲解。
  • raw.c文件实现了一个传输层协议的框架,我们可以在它的基础上修改和添加代码,实现自定义的传输层协议,与UDP/TCP一样,它可以与IP层直接进行交互。这类似RAW Socket。在实际的应用中,我们常用UDP和TCP作为传输层协议。但有时,底层网络开发人员会嫌UDP的可靠性太差,或者TCP虽然可靠性强,但是很耗费时间和内存,他们需要根据实际需求,平衡利弊,定义自己的传输层协议。LwIP的raw模块可以满足他们的需求。
  • tcp.c、tcp_in.c和tcp_out.c文件实现了TCP协议,包括对TCP连接的操作、对TCP数据包的输入输出操作和TCP定时器,它们和include目录中名称带tcp的头文件共同构成了LwIP的TCP模块。TCP模块的实现是LwIP的最大特点,它以很小的资源开销几乎实现了TCP协议中规定的全部内容。TCP协议是非常复杂的协议,这几个与TCP模块相关的文件占据了LwIP内核的绝大部分。

lwip 数据包(pbuf)
  • pbuf就是一个描述协议栈中数据包的数据结构,LwIP中在pbuf.c和pubf.h实现了协议栈数据包管理的所有函数与数据结构,
    在这里插入图片描述

在这里插入图片描述

  • 作者想要提醒一下大家,对于一个数据包,它可能会使用任意类型的pbuf进行描述,也可能使用多种不同的pbuf一起描述
    在这里插入图片描述

LwIP不仅能在裸机上运行,也能在操作系统环境下运行,而且在操作系统环境下,用户能使用NETCONN API 与Socket API编程,相比RAW API编程会更加简便。操作系统环境下,这意味着多线程环境,一般来说LwIP作为一个独立的处理线程运行,用户程序也独立为一个/多个线程,这样子在操作系统中就相互独立开,并且借助操作系统的IPC通信机制,更好地实现功能的需求。

在操作系统环境下,LwIP会作为一个线程运行,线程的名字叫tcpip_thread,在初始化LwIP的时候,内核就会自动创建这个线程,并且在线程运行的时候阻塞在邮箱上,等待数据进行处理,这个邮箱数据的来源可能在底层网卡接收到的数据或者上层应用程序的数据,总之,tcpip_thread线程在获取到邮箱中的数据时候,就会退出阻塞态,去处理数据,在处理完毕数据后又进入阻塞态中等待数据的到来,如此反复。

LwIP是这样子处理的,如果已经发生超时,LwIP就会内部调用sys_check_timeouts()函数去检查超时的sys_timeo结构体并调用其对应的回调函数,如果没有发生超时,那就一直等待消息,其等待的时间为下一个超时时间的时间,一举两得。 LwIP中tcpip线程就是靠这种方法,即处理了上层及底层的tcpip_mbox消息,同时处理了所有需要超时处理的事件。

ARP表也包含一个寿命(TTL)值,它指示了从表中删除每个映射的时间。从一个表项放置到某ARP表中开始,一个表项通常的过期时间是10分钟。


使用NETCONN接口编程
使用Socket接口编程
使用RAW API接口编
  • RAW API是基于回调函数实现的API接口,它是很底层的API接口,这需要开发者对LwIP有较深的了解才能很好使用它,RAW API的核心就是对控制块的处理,因为对于报文数据的处理、注册回调函数等都是需要开发者自己去实现,都是比较麻烦的,但是有一个优点,那就是处理数据效率高

linux下有两个网卡A和B, 怎么把A网卡的数据转发给B网卡 ?
  • 一个应用场景是在 Linux 上用 IP转发使内部网络连接到互联网
  1. 确认两个网卡的名称,可以使用 ifconfigip addr 命令查看网卡信息。
  2. 开启 IP 转发功能。在命令行输入以下命令:echo 1 > /proc/sys/net/ipv4/ip_forward 这将启用 IP 转发功能。
  3. 配置转发规则。使用 iptables 命令来实现,例如:iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT 这个命令的意思是将来自 eth0 网卡的数据包转发到 eth1 网卡上,并且允许这个过程。
  4. 测试。现在可以测试转发是否正常工作,例如从连接在 A 网卡的设备发送一些数据包,看看是否能够从连接在 B 网卡的设备接收到这些数据包。

请注意,这只是基本的转发设置,具体的设置还需要根据实际情况进行调整。此外,也需要确保网络环境和安全性,以避免不必要的风险。


参考资料
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值