一、Lwip——简介
1 LwIP介绍
LwIP全名:Light weight IP,意思是轻量化的TCP/IP协议,是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。LwIP的设计初衷是:用少量的资源消耗实现一个较为完整的TCP/IP协议栈,其中“完整”主要指的是TCP协议的完整性,实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。此外LwIP既可以移植到操作系统上运行,也可以在无操作系统的情况下独立运行。
LwIP具有主要特性:
-
支持ARP协议(以太网地址解析协议)
-
支持ICMP协议(控制报文协议),用于网络的调试与维护。
-
支持IGMP协议(互联网组管理协议),可以实现多播数据的接收。
-
支持UDP协议(用户数据报协议)。
-
支持TCP协议(传输控制协议),包括阻塞控制、RTT 估算、快速恢复和快速转发。
-
支持PPP协议(点对点通信协议),支持PPPoE。
-
支持DNS(域名解析)。
-
支持DHCP协议,动态分配IP地址。
-
支持IP协议,包括IPv4、IPv6协议,支持IP分片与重装功能,多网络接口下的数据包转发。
-
支持SNMP协议(简单网络管理协议)。
-
支持AUTOIP,自动IP地址配置。
-
提供专门的内部回调接口(Raw API),用于提高应用程序性能。
-
提供可选择的Socket API、NETCONN API (在多线程情况下使用) 。
LwIP在嵌入式中使用有以下优点:
-
资源开销低,即轻量化。LwIP内核有自己的内存管理策略和数据包管理策略, 使得内核处理数据包的效率很高。另外,LwIP高度可剪裁,一切不需要的功能都可以通过宏编译选项去掉。 LwIP的流畅运行需要40KB的代码ROM和几十KB的RAM,这让它非常适合用在内存资源受限的嵌入式设备中。
-
支持的协议较为完整。几乎支持TCP/IP中所有常见的协议,这在嵌入式设备中早已够用。
-
实现了一些常见的应用程序:DHCP客户端、DNS客户端、HTTP服务器、MQTT客户端、TFTP服务器、SNTP客户端等等。
-
同时提供了三种编程接口:RAW API、NETCONN API(注:NETCONN API即为Sequential API,为了统一,下文均采用NETCONN API)和Socket API。这三种API的执行效率、易用性、可移植性以及时空间的开销各不相同,用户可以根据实际需要,平衡利弊,选择合适的API进行网络应用程序的开发。
-
高度可移植。其源代码全部用C实现,用户可以很方便地实现跨处理器、跨编译器的移植。 另外,它对内核中会使用到操作系统功能的地方进行了抽象,使用了一套自定义的API, 用户可以通过自己实现这些API,从而实现跨操作系统的移植工作。
-
开源、免费,用户可以不用承担任何商业风险地使用它。
-
相比于嵌入式领域其它的TCP/IP协议栈,比如uC-TCP/IP、FreeRTOS-TCP等, LwIP的发展历史要更悠久一些,得到了更多的验证和测试。LwIP被广泛用在嵌入式网络设备中, 国内一些物联网公司推出的物联网操作系统,其TCP/IP核心就是LwIP;物联网知名的WiFi模块ESP8266,其TCP/IP固件,使用的就是LwIP。
LwIP尽管有如此多的优点,但它毕竟是为嵌入式而生,所以并没有很完整地实现TCP/IP协议栈。相比于Linux和Windows系统自带的TCP/IP协议栈,LwIP的功能不算完整和强大。但对于大多数物联网领域的网络应用程序,LwIP已经足够了。
2 LwIP的三种编程接口
主要是需要区分以下三种API,后续章节会使用LwIP提供了三种编程接口,分别为RAW/Callback API、NETCONN API、SOCKET API。它们的易用性从左到右依次提高,而执行效率从左到右依次降低,用户可以根据实际情况,平衡利弊,选择合适的API进行网络应用程序的开发。以下内容将分别介绍这三种API。
2.1 RAW/Callback API
RAW/Callback API是指内核回调型(用户注册回调函数、系统会调用回调函数执行)的API,这在许多通信协议的C语言实现中都有所应用。
LwIP内核把数据交给应用程序的过程就只是一次简单的函数调用,这是非常节省时间和空间资源的。每一个回调函数实际上只是一个普通的C函数,这个函数在TCP/IP内核中被调用。每一个回调函数都作为一个参数传递给当前TCP或UDP连接。而且,为了能够保存程序的特定状态,可以向回调函数传递一个指定的状态,并且这个指定的状态是独立于TCP/IP协议栈的。。
在有操作系统的环境中,如果使用RAW/Callback API,用户的应用程序就以回调函数的形式成为了内核代码的一部分,用户应用程序和内核程序会处于同一个线程之中,这就省去了任务间通信和切换任务的开销了。
简单来说,RAW/Callback API的优点有两个:
-
可以在没有操作系统的环境中使用。
-
在有操作系统的环境中使用它,对比另外两种API,可以提高应用程序的效率、节省内存开销。
RAW/Callback API的优点是显著的,但缺点也是显著的:
-
基于回调函数开发应用程序时的思维过程比较复杂。在后面与RAW/Callback API相关的章节中可以看到,利用回调函数去实现复杂的业务逻辑时,会很麻烦,而且代码的可读性较差。
-
在操作系统环境中,应用程序代码与内核代码处于同一个线程,虽然能够节省任务间通信和切换任务的开销,但是相应地,应用程序的执行会制约内核程序的执行,不同的应用程序之间也会互相制约。在应用程序执行的过程中,内核程序将不可能得到运行,这会影响网络数据包的处理效率。如果应用程序占用的时间过长,而且碰巧这时又有大量的数据包到达,由于内核代码长期得不到执行,网卡接收缓存里的数据包就持续积累,到最后很可能因为满载而丢弃一些数据包,从而造成丢包的现象。
2.2 NETCONN API
在操作系统环境中,可以使用NETCONN API或者Socket API进行网络应用程序的开发。NETCONN API是基于操作系统的IPC机制(即信号量和邮箱机制)实现的,它的设计将LwIP内核代码和网络应用程序分离成了独立的线程。如此一来,LwIP内核线程就只负责数据包的TCP/IP封装和拆封,而不用进行数据的应用层处理,大大提高了系统对网络数据包的处理效率。
前面提到,使用RAW/Callback API会造成内核程序和网络应用程序、不同网络应用程序之间的相互制约,如果使用NETCONN API或者Socket API,这种制约将不复存在。
在操作系统环境中,LwIP内核会被实现为一个独立的线程,名为tcpip_thread,使用NETCONN API或者Socket API的应用程序处在不同的线程中,我们可以根据任务的重要性,分配不同的优先级给这些线程,从而保证重要任务的时效性,分配优先级如下:
线程 | 优先级 |
---|---|
LwIP内核线程tcpip_thread | 很高 |
重要的网络应用程序 | 高 |
不太重要而且处理数据比较耗时的网络应用程序 | 低 |
NETCONN API使用了操作系统的IPC机制,对网络连接进行了抽象,用户可以像操作文件一样操作网络连接(打开/关闭、读/写数据)。但是NETCONN API并不如操作文件的API那样简单易用。举个例子,调用f_read函数读文件时,读到的数据会被放在一个用户指定的数组中,用户操作起来很方便,而NETCONN API的读数据API,就没有那么人性化了。用户获得的不是一个数组,而是一个特殊的数据结构netbuf,用户如果想使用好它,就需要对内核的pbuf和netbuf结构体有所了解,我们会在后续的章节中对它们进行讲解。NETCONN API之所以采取这种不人性的设计,是为了避免数据包在内核程序和应用程序之间发生拷贝,从而降低程序运行效率。当然,用户如果不在意数据递交时的效率问题,也可以把netbuf中的数据取出来拷贝到一个数组中,然后去处理这个数组。
简单来说,NETCONN API的优缺点是:
-
相较于RAW/Callback API,NETCONN API简化了编程工作,使用户可以按照操作文件的方式来操作网络连接。但是,内核程序和网络应用程序之间的数据包传递,需要依靠操作系统的信号量和邮箱机制完成,这需要耗费更多的时间和内存,另外还要加上任务切换的时间开销,效率较低。
-
相较于Socket API,NETCONN API避免了内核程序和网络应用程序之间的数据拷贝,提高了数据递交的效率。但是,NETCONN API的易用性不如Socket API好,它需要用户对LwIP内核所使用数据结构有一定的了解。
2.3 SOCKET API
Socket,即套接字,它对网络连接进行了高级的抽象,使得用户可以像操作文件一样操作网络连接。它十分易用,许多网络开发人员最早接触的就是Socket编程,Socket已经成为了网络编程的标准。在不同的系统中,运行着不同的TCP/IP协议,但是只要它实现了Socket的接口,那么用Socket编写的网络应用程序就能在其中运行。可见用Socket编写的网络应用程序具有很好的可移植性。
不同的系统有自己的一套Socket接口。Windows系统中支持的是WinSock,UNIX/Linux系统中支持的是BSD Socket,它们虽然风格不一致,但大同小异。LwIP中的Socket API是BSD Socket。但是LwIP并没有也没办法实现全部的BSD Socket,如果开发人员想要移植UNIX/Linux系统中的网络应用程序到使用LwIP的系统中,就要注意这一点。
相较于NETCONN API, Socket API具有更好的易用性。使用Socket API编写的程序可读性好,便于维护,也便于移植到其它的系统中。Socket API在内核程序和应用程序之间存在数据的拷贝,这会降低数据递交的效率。另外,LwIP的Socket API是基于NETCONN API实现的,所以效率上相较前者要打个折扣。
https://www.cnblogs.com/The-explosion/p/13582525.html