我阅读的代码是最新的2.1.2版本,下载链接如下:
http://download.savannah.nongnu.org/releases/lwip/
事情调试环境是正点原子STM32F407开拓板,一边在开拓板上调试,一边printf打印输出。

Lwip整体架构如下图所示:
一、 MCU的业务层
这一层是lwip供应做事的工具,便是自己的业务代码利用lwip的地方。业务代码从这里开始通过netconn或是lwip_api接口开始调用lwip的功能。比如,范例的TCP客户端首先通过netconn_new创建一个struct netconn工具,接着调用netconn_connect连接做事器,连接成功后调用netconn_write向做事器发送数据,或者调用netconn_recv吸收数据,末了,通过netconn_close关闭连接,开释资源。
二、lwIP的api层
这一层是netconn的功能代码所在地方,供应netconn的api给上层代码利用。如果习气了利用socket的同学可以用lwip_socket等函数按标准socket的办法调用lwip的功能。而且,在新的版本里增加了http,mqtt等运用的代码,这些附加的运用对现在的物联网通讯来说真的是方便了不少。
三、lwip的核心层
这一层是TCP/IP的协议栈的核心代码所在的地方,不单实现了险些全部的TCP,UDP功能,还实现了ICMP,IGMP等协议。同时,还有mem内存管理,netif网络接口功能。这一层供应了一个针对各平台移植的sys_arch模块,以便于把lwIP移植到不同的操作系统中去。比如,实现线程的创建,旗子暗记灯,行列步队等功能,这些都是和平台密切干系的,与操作系统干系的接口定义写在lwip/include/sys.h文件里。
四、硬件驱动层
这一层供应了PHY芯片的驱动,以供lwip的利用。lwip会调用这一层的代码把组好的数据包发送到网络,同时也会通过这一层实现从网络收到数据包并加以剖析各协议,实现通讯功能。
Lwip功能很多也很强大,下面大略地讲一下TCP数据收发的一个过程
发送,如下图所示:
(a) 运用代码调用netconn_write接口,把数据等参数传入,lwip检讨连接是不是壅塞等,如果不是壅塞的直接返回缺点,如果是壅塞则发送然后等待,通过行列步队切换实行流,由lwip线程把实行流走到lwip_netconn_do_write函数中去。这个函数检讨当前数据有效性等,假设统统都精确,将调用tcp_write函数,由tcp模块进一步处理和打包数据。处理完成后,调用tcp_output向下层发送数据。
(b) TCP模块从tcp_write进入后,将实行tcp协议栈的详细功能,里面的逻辑比较多也比较繁芜,如果只是出于对代码移植和利用,这些代码根本不须要改动。在tcp模块功能完成后比如准备缓冲器,填写校验和等,成功返回。
TCP模块从tcp_output进入后,将根据本地地址,目标地址等找到适宜的路由的网络接口netif实例,把netif接口当作参数一起调用到ip模块,让数据往下发送。在lwip的设计中,一个实际的网卡PHY芯片便是对应一个netif实例。
(c) IP模块从ip_output_if函数进入后,检讨如果是ipv4的数据则调用ip4_output_if,准备好ip包头,可选的ip包头等信息,然后,调用网络接口netif->output函数连续发送数据包。
(d) 网络接口netif模块根据PCB配置的网卡通过netif_add函数加入到lwip中,根据网络硬件的不同而实现不同的功能,如果网卡因此太网phy芯片,则把netif->output函数设置成etharp_output函数,由以太网ethernet模块去组装以太网帧,管理arp地址列表等。
(e) ethernet模块卖力数据链路层的数据剖析与组包,当数据组好以太网帧后,调用网络接口netif->linkeoutput函数,把数据通过网口芯片发送出去。
(f) 正点原子STM32F407的开拓板的网络PHY芯片把网络接口netif->linkeoutput函数设置成low_level_output,所有数据末了通过low_level_output函数把它发送到PHY芯片并终极发送到网络。
吸收,如下图所示:
1、运用代码调用netconn_recv吸收网络数据,此函数分配一块缓冲器,然后通过调用sys_arch_mbox_fetch等待行列步队的返回。数据收到后,从行列步队返回,并包含有数据的缓存区。
2、sys_arch_mbox_fetch等待行列步队中的,是lwip须要实现的一个与平台干系的功能,在sys_arch模块中实现和管理,卖力实现操作系统行列步队。
另一方面网络数据到达网卡的数据流如下:
a、数据通过网络到达网卡PHY芯片,这时触发MCU的一个中断。
b、 中断例程通过调用ethernetif_input函数关照lwip数据到达netif网络接口。
c、通过low_level_input函数获取网络数据。
d、ETH_Rx_Packet函数实现PHY的驱动,获取数据,每种芯片可能有不同的实现。
e、网络接口netif模块根据网卡芯片的不同,配置不同的netif->input函数,如果因此太网phy芯片,则配成是ethernet_input,由于phy芯片每一帧都因此太网帧,里面包含以太帧的全部信息,包括目的MAC地址及源MAC地址等。
f、ethernet模块把以太网帧的包头等信息去掉,并检讨数据精确性之后,如果是IP包,则调用ip4_input函数,把数据往上传。IP的上层协议比较多,有udp,tcp,icmp,igmp等等,如果是TCP数据,则调用tcp_input操纵续把数据往上传。
g、TCP模块比较繁芜,收到TCP包后,不单要发送ack,还有可能要发送重传信息等。同时,为了网络性能,还要调度滑动窗口。数据处理完并且都精确后连续往上传。
h、数据通过TCP_EVENT_RECV宏关照lwip有TCP事宜到达。TCP_EVENT_RECV宏定义成通过tcp_pcb->recv函数实行事宜。此函数在netconn中配成recv_tcp。在recv_tcp函数里面调用sys_mbox_trypost函数关照数据吸收完毕。这时上层代码可以唤醒吸收数据了。
i、sys_mbox_trypost函数是一个与操作系统干系的函数,大部分的操作系统基本都有行列步队的功能,但每个操作系统的实现办法都不一样。
至此,lwip基本的收发功能基本走了一遍,协议栈中更详细的逻辑没有剖析,这和移植没有什么关系了,往后有更深入的项目的须要,再去研究里面的代码吧。