当前位置:   article > 正文

STM32+Nano版RT-thread+LWIP移植说明_rtthread lwip

rtthread lwip

STM32+Nano版RT-thread+LWIP移植说明

一、Nano版RT-thread移植

关于RT-thread驱动移植可参考上期内容HC32F460 RT-Thread Nano版移植,这里就不详细说明了。

二、LWIP移植(1.4.1)

2-1 TCP/IP协议及LWIP简介

1、TCP/IP协议简介
TCP/IP:传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议,由网络层的IP协议和传输层的TCP协议组成,定义了电子设备如何连入因特网以及数据如何在它们之间传输的标准。但是,值得注意的是TCP/IP协议不是TCP和IP这两个协议的合称。而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议,下图为分层模型。
在这里插入图片描述
•网络接口层
对电信号进行分组并形成具有特定意义的数据帧,然后以广播的形式通过物理介质发送给接收方。
•网络层
定义网络地址、区分网段、子网内MAC寻址、对于不同子网的数据包进行路由。
•传输层
定义端口,标识应用程序身份,实现端口到端口的通信,TCP协议保证数据传输可靠性。
•应用层
定义数据格式并按照对应的格式解读数据。

2、LWIP简介
LwIP是轻量化的 TCP/IP 协议,是一个小型开源的 TCP/IP 协议栈。LwIP 的设计初衷是:用少量的资源消耗(RAM)实现一个较为完整的 TCP/IP 协议栈,其中“完整”主要指的是 TCP 协议的完整性, 实现的重点是在保持 TCP 协议主要功能的基础上减少对 RAM 的占用。此外 LwIP既可以移植到操作系统上运行,也可以在无操作系统的情况下独立运行。它只需十几KB的RAM和40K左右的ROM就可以运行,这使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主要优点
资源开销低,高度可剪裁,适合用在内存资源受限的嵌入式设备中。
支持的协议较为完整。几乎支持 TCP/IP 中所有常见的协议,在嵌入式设备中早已够用。
实现了一些常见的应用程序: DHCP 客户端、 DNS 客户端、 HTTP 服务器等等。
同时提供了三种编程接口: RAW API(主要无操作系统)、 NETCONN API 和 Socket API。
高度可移植。其源代码全部用 C 实现,用户很方便地实现跨处理器、跨编译器的移植。
开源、免费,用户可以不用承担任何商业风险地使用它。
LwIP 的发展历史要更悠久一些,得到了更多的验证和测试。

•LWIP源码下载
LWIP源码
http://savannah.nongnu.org/projects/lwip/
其中lwip-1.4.1(源码包), contrib-1.4.1(contrib 包里面装的是移植和应用 LwIP 的一些 demo,即应用示例。contrib包不属于LwIP 内核的一部分,里面的很多内容来自开源社区的贡献,因此 contrib 包的版本管理不像内核源码那样严格和规范,但也是很有参考价值的。)

•LWIP源码文件说明
CHANGELOG 文件记录了 LwIP 在版本升级过程中源代码发生的变化。
COPYING 文件记录了 LwIP 这个开源软件的 license遵守一定的规则。
FILES 文件用于介绍当前目录下的目录信息。
README 文件对 LwIP 进行了一个简单的介绍。
UPGRADING 文件记录了 LwIP 每个大版本的更新,会对使用和移植 LwIP 造成的影响。
doc 文件夹里面是关于 LwIP 的一些文档,可以看成是应用和移植 LwIP 的指南。
test 文件夹里面是测试 LwIP 内核性能的源码。
src 文件夹里面就是我们最关心的 LwIP 源码文件。文件目录如下:
在这里插入图片描述

api 文件夹里面装的是 NETCONN API 和 Socket API 相关的源文件,用在操作系统中。
core TCP/IP 协议栈的核心部分。
Include LwIP使用的各种头文件。
Netif 主要包含通用网络接口设备驱动程序。注意:这个文件夹中的函数并不能使用, 它们都是一个框架性的结构, 移植者需要根据自己使用的网 卡特性来完成这些函数。
其中ethernetif.c : 包含了与以太网网卡密切相关的初始化、发送、接收等函数的实现(本次移植需要修改)。

2-2 添加网卡程序

1、硬件方案
在这里插入图片描述

2、MAC驱动实现
在这里插入图片描述

STM32自带以太网模块,主要通过添加drv_rth_mac.c并实现以下函数功能。
在这里插入图片描述

3、PHY驱动实现
在这里插入图片描述

本次方案采用DP83848以太网收发器,通过添加dp83848.c实现以下函数功能。注意:RMII接口 和DP83848 PHY芯片地址(4个PHYAD引脚,0000~1111).根据核心板硬件连接决定。
在这里插入图片描述

2-3 添加LWIP源文件

1、添加LWIP API
在这里插入图片描述

api_lib.c: 含对外提供的 sequential API 函数的实现。函数名均以netconn_开头(TCP、UDP)。
api_msg.c:含sequential API内部自己调用函数的实现。主要含API消息的封装和处理函数。
err.c: 错误管理模块
netbuf.c: 包含了上层数据包管理函数的实现。应用程序描述数据的基本结构(pbuf)。
netdb.c: 包含与主机名字转换相关的函数,主要在 socket 中被使用到。
netifapi.c: 包含了上层网络接口管理函数的实现。
sockets.c: 包含了 Socket API 函数的实现。
tcpip.c: 包含了上层 API 与协议栈内核交互的函数,它是整个上层 API 功能得以实现的一个枢纽,从 API 函数处接收消息(通过邮箱),然后将消息递交给内核函数,内核函数根据消息做出相应的处理。

2、添加LWIP CORE
在这里插入图片描述

autoip.c: 这是lwIP TCP / IP协议栈的AutoIP实现。
icmp.c: 包含了ICMP 协议实现的相关函数。(IP数据传递中差错报告、差错纠正等)
igmp.c: 包含了网络组管理协议IGMP 的实现。
inet.c: 目前没有啥实际内容。
inet_chksum.c: 这些是校验和算法的一些参考实现。
ip.c: IPv4和IPv6共用的代码。
ip_addr.c: 实现了几个比较简单 的IP 地址处理函数。
def.c: 包含IP 层使用到的一些函数的定义,IP 地址转换、网络与主机字节序转换等。
dhcp.c: 实现了DHCP动态主机配置协议客户端的代码,从DHCP 服务器处获得IP 地址。
dns.c: 实现了DNS 客户端的所有代码,DNS 称为域名系统。
init.c: 包含了一个与LwIP 协议栈初始化相关的函数,以及协议栈配置信息的检查与输出。
mem.c: 包含了协议栈内存堆管理函数的实现。
memp.c: 包含了协议栈内存池管理函数的实现。
netif.c: 包含了协议栈网络接口管理的相关函数。
pbuf.c: 包含了协议栈内核使用的数据包管理函数,采用特殊的数据包pbuf 结构。
raw.c: 为应用层提供了一种直接和IP 数据包交互的方式,LwIP最底层的API部分。
stats.c: 包含了协议栈内部数据统计与显示的相关函数,如内存使用状况、邮箱、信号量等。
tcp: 包含了对TCP 控制块操作的函数,也包括了TCP 定时处理函数。
tcp_in.c: 包含了TCP 协议中数据接收、处理相关的函数,最重要的TCP 状态机函数。
tcp_out.c: 包含了TCP 中数据发送相关的函数,例如数据包发送函数、超时重传函数等。
Timer.c: 统一了对内核各个协议定时事件处理函数的封装,对注册的定时事件进行处理。
udp.c: 包含了实现UDP 协议的相关函数。
sys.c: 一个简单的函数,借助操作系统模拟层的信号量机制完成睡眠(无操作系统不编译)。

3、添加LWIP NETIF
在这里插入图片描述

etharp.c: 包含了ARP 协议实现的相关函数,ARP 协议是以太网通信中的重要部分, 主要用来实现主机以太网物理地址到IP 地址的映射。
ethernetif.c : 包含了与以太网网卡密切相关的初始化、发送、接收等函数的实现。注意:这个文件夹中的函数并不能使用, 它们都是一个框架性的结构, 移植者需要根据自己使用的网卡特性来完成这些函数。

4、修改LWIP 部分源码
•ethernetif.c
LwIP的网络驱动的模版,根据实际网卡驱动实现,在 LwIP中可以有多个网络接口,每个网络接口都对应了一个struct netif。这个netif包含了相应网络接口的属性、收发函数。
LowLevelInit:主要完成网卡的复位,协议栈网络接口管理结构体netif中相关字段的初始化。
LowLevelOutput:用于发送数据,将LWIP协议栈准备好的数据(存储为pbuf结构)通过网卡发送出去。
LowLevelInput:从网卡中提取数据,并封装在pbuf结构中供LWIP使用。
EthernetifInput:主要对LowLevelInput函数做封装,将接收到数据送入指定的网卡结构中。
EthernetifInit:主要对LowLevelInit函数封装,初始化netif相关字段。

•mem.c
在这里插入图片描述

LWIP的内存堆我们改为动态分配方式,把数组改为指针。
•memp.c
在这里插入图片描述

LWIP的内存池我们改为动态分配方式,把数组改为指针,并增加memp_get_memorysize得到memp_memory数组大小。
•icmp.c
在这里插入图片描述

修改支持硬件帧校验。

2-4 添加LWIP中间文件

1、添加ARCH文件(CPU或编译器相关接口)
•cc.h
主要完成协议栈内部使用的数据类型定义,如果使用操作系统还有临界代码区保护等等。
•cpu.h
用来定义cpu的大小端模式,STM32是小端模式,定义BYTE_ORDER。
•perf.h
和系统测量与统计相关的文件,我们不使用该功能,这个文件两宏定义为空。
•sys_arch.h、sys_arch.c
使用操作系统使用的文件,我们移植需要实现(根据sys_arch.txt文档)。
在这里插入图片描述

sys_arch.c操作系统抽象层:主要为协议栈提供邮箱、信号量等机制(此文件为协议栈的一部分),内核线程创建、内核保护,具体实现见代码,我们采用RTthrad。
err_t sys_mbox_new( sys_mbox_t *mbox, int size)
void sys_mbox_free(sys_mbox_t * mbox)
void sys_mbox_post(sys_mbox_t *mbox,void *msg)
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
int sys_mbox_valid(sys_mbox_t *mbox)
void sys_mbox_set_invalid(sys_mbox_t *mbox)
err_t sys_sem_new(sys_sem_t * sem, u8_t count)
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
void sys_sem_signal(sys_sem_t *sem)
void sys_sem_free(sys_sem_t *sem)
int sys_sem_valid(sys_sem_t *sem)
void sys_sem_set_invalid(sys_sem_t *sem)
err_t sys_mutex_new(sys_mutex_t *mutex)
void sys_mutex_free(sys_mutex_t *mutex)
void sys_mutex_lock(sys_mutex_t *mutex)
void sys_mutex_unlock(sys_mutex_t *mutex)
void sys_init(void)
sys_prot_t sys_arch_protect(void)
void sys_arch_unprotect(sys_prot_t pval)
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
u32_t sys_now(void)

2、添加LWIP通用文件(自己添加)
•lwip_comm.h、lwip_comm.c
将LWIP源码和以太网驱动结合起来的桥梁。
1、主要结构体实现
//lwip控制结构体
typedef struct
{
u8 Mac[6]; //MAC地址
u8 RemoteIp[4]; //远端主机IP地址
u8 Ip[4]; //本机IP地址
u8 NetMask[4]; //子网掩码
u8 GateWay[4]; //默认网关的IP地址

vu8 DhcpStatus;	//dhcp状态 
				//0,未获取DHCP地址;
				//1,进入DHCP获取状态
				//2,成功获取DHCP地址
				//0XFF,获取失败.
  • 1
  • 2
  • 3
  • 4
  • 5

}Lwip_Dev_Typedef;

2、主要函数实现(具体见代码)
static void LwipCommMemFree(void)
完成了对mem.c、memp.c中内存堆ram heap和内存池memp_memory的内存释放。
static u8 LwipCommMemMalloc(void)
完成了对mem.c、memp.c中内存堆ram heap和内存池memp_memory的内存申请。
static void LwipCommDefaultIpSet(Lwip_Dev_Typedef lwipx)
设置默认地址,即控制结构体Lwip_Dev_Typedef成员变量值。
static void LwipPktHandle(void)
接收数据回调函数,对EthernetifInput简单封装,从指定网络接口接收数据。
static void LwipCommDhcpDelete(u8 owner)
删除DHCP任务,使能DHCP并使用操作系统时有效。
static void LwipDhcpTask(void
parameter)
DHCP处理任务,使能DHCP并使用操作系统时有效。
static void LwipCommDhcpCreat(void)
创建DHCP任务,使能DHCP并使用操作系统时有效。
static void LwipDhcpProcessHandle(void)
DHCP处理任务,使能DHCP并不使用操作系统时有效。
void LwipPeriodicHandle(void)
LWIP轮询任务(10ms,内核中周期定时器,TCP、ARP、DHCP),LWIP协议栈要求每250ms处理一次TCP定时器,每5S处理一次ARP定时器,每500ms一次DHCP精细处理定时器,每60s执行一次DHCP粗糙处理,不使用操作系统时有效。
u8 LwipCommInit(void)
主要完成LWIP内核初始化,设置默认网卡并且打开指定的网卡,详见如下代码实现。

/*==================================================================
* Function      : LwipCommInit
* Description   : LWIP初始化(LWIP启动的时候使用)
* Input Para    : none
* Output Para   : none
* Return Value  : 0,成功 1,内存错误 2,DB83848初始化失败 3,网卡添加失败
==================================================================*/
u8 LwipCommInit(void)
{
    //调用netif_add()函数时的返回值,用于判断网络初始化是否成功
    struct netif *NetifInitFlag;
    //ip地址
    struct ip_addr IpAddr; 
    //子网掩码
	struct ip_addr NetMask;
    //默认网关 
	struct ip_addr Gw;      			
    //1.网卡驱动内存申请
    if(Dp83848MemMalloc()) return 1;
    //2.lwip内存申请
    if(LwipCommMemMalloc())return 1;
    //3.初始化DP83848 
	if(Dp83848Init())return 2;    
    //4.初始化LWIP内核
    //使用操作系统
    #if !NO_SYS
    //初始化tcp ip内核,该函数里面会创建tcpip_thread内核任务
    tcpip_init(NULL,NULL);				
    #else
    lwip_init();
    #endif
    //5.设置默认IP等信息
    LwipCommDefaultIpSet(&gLwipDev);
    //6.DHCP
    //使用动态IP
#if LWIP_DHCP		
	IpAddr.addr = 0;
	NetMask.addr = 0;
	Gw.addr = 0;
    //使用静态IP 
#else				 
	IP4_ADDR(&IpAddr,gLwipDev.Ip[0],gLwipDev.Ip[1],gLwipDev.Ip[2],gLwipDev.Ip[3]);
	IP4_ADDR(&NetMask,gLwipDev.NetMask[0],gLwipDev.NetMask[1] ,gLwipDev.NetMask[2],gLwipDev.NetMask[3]);
	IP4_ADDR(&Gw,gLwipDev.GateWay[0],gLwipDev.GateWay[1],gLwipDev.GateWay[2],gLwipDev.GateWay[3]);
#endif 
    //7.设置网卡接收数据回调函数
    Dp83848Banding(LwipPktHandle);
    //8.向网卡列表中添加一个网口    
//不使用操作系统    
#if NO_SYS     
    NetifInitFlag=netif_add(&gLwipNetif,&IpAddr,&NetMask,&Gw,NULL,&EthernetifInit,&ethernet_input);
//如果使用DHCP的话
#if LWIP_DHCP
    //DHCP标记为0
	gLwipDev.DhcpStatus=0;
	//开启DHCP服务
	dhcp_start(&gLwipNetif);	
#endif 
#else
    NetifInitFlag=netif_add(&gLwipNetif,&IpAddr,&NetMask,&Gw,NULL,&EthernetifInit,&tcpip_input);
#endif
    //网卡添加失败 
    if(NetifInitFlag==NULL)return 3;
    //8.网口添加成功后,设置netif为默认值,并且打开netif网口
	else
	{
        //设置netif为默认网口
		netif_set_default(&gLwipNetif);
        //打开netif网口
		netif_set_up(&gLwipNetif);		
	}
    //使用操作系统
    #if !NO_SYS
    //创建DHCP任务
    LwipCommDhcpCreat();
    #endif
    //操作OK.
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

2-5 添加LWIP配置文件

在这里插入图片描述

在LWIP源码中有opt.h文件来裁剪和配置LWIP,我们重新增加lwipopts.h通过条件编译来实现配置LWIP,从而不直接修改opt.h文件,具体可根据实际使用修改。
在这里插入图片描述

三、LWIP软件说明

3-1数据帧格式

1、以太网数据帧格式
在这里插入图片描述
在这里插入图片描述

前两个字段由网卡在物理层上发送以太网数据时添加上去的。
前同步码 SFD帧开始定界符 目的地址 源地址 长度/类型 数据和填充 CRC
7字节 1字节 6字节 6字节 2字节 46字节~1500字节 4字节
前同步码7+1字节硬件添加的,作用是为了通知接收方:”MAC帧要来了,做好接受的准备“,与MAC帧当中的其它内容都无关
目的地址:单播地址、多播地址、广播地址(etharp_output)
单播地址:第一字节的bit0为0
多播地址:第一字节的bit0为1
广播地址:48位全为1
长度或类型字段:小于1518表示长度,大于1518表示上层协议类型,0x800表示IP数据包,0x806表示ARP数据包。
数据和填充字段:最小长度46字节,最大长度1500字节。
CRC字段,它的检验范围是不包括八个字节的前同步码的。

2、ARP数据帧格式
在这里插入图片描述
在这里插入图片描述

ARP包封装在以太网帧中发送。
以太网目的地址 以太网源地址 帧类型 硬件类型 协议类型 硬件地址长度 协议地址长度 OP 发送方以太网地址 发送方IP地址 接收方以太网地址 接收方IP地址
6字节 6 2 2 2 1 1 2 6 4 6 4
以太网首部 28字节ARP数据包

以太网目的地址:全为1的以太网广播地址。
以太网帧类型:0x0806-ARP包, 0x0800-IP包。
硬件地址长度和协议地址长度,对于ARP请求或应答,分别为6和4,代码MAC长度和IP长度。
OP操作字段:ARP数据包类型,1-请求 2-应答 3-RARP请求 4-RARP应答,RARP为逆地址解析协议。

3、IP数据帧格式
在这里插入图片描述

IP包封装在以太网帧中发送。
在这里插入图片描述

版本号(4位) 首部长度(4位) 服务类型(8位) 总长度(16位)
标识(16位) 标志(3位) 分片偏移量(13位)
生存时间TTL(8位) 协议8位 首部校验和(16位)
源IP地址(32位)
目的IP地址(32位)
选项地址(若存在)
数据区
版本号:IP协议版本信息。
首部长度:对于不含选项字段的IP首部,长度值为5.(5*4 = 20字节)。
服务类型:路由器在转发过程中,根据服务类型选择合理的路由路径。
总长度:整个IP数据包(IP首部和数据区)的总字节数。
标识:每发送一份报文加1,分片时,接收端使用该字段组装分片。
标志:第一位保留,第二位不分片时为1,不能分片,若物理层无法处理直接丢弃,为0,可分片,第三位更多分片位,为1表示不是最后一个分片,为0表示最后一个分片或唯一分片。
偏移字段:表示当前数据在整个数据报中相对位置(8字节为单位)。
生存时间:该数据包最多被转发次数,每转一次,减去1,为0时,路由器会丢弃分组,同时一个ICMP差错报文返回源主机。
协议:用来描述IP数据包中所属上层协议类型,1-ICMP协议,2-IGMP协议,6-TCP协议,17-UDP协议。
首部校验和:只针对IP首部做校验,内部数据由上层协议负责校验。

4、UDP数据帧格式
在这里插入图片描述
在这里插入图片描述

源端口号 目的端口号
总长度 校验和
数据区

5、TCP数据帧格式
在这里插入图片描述
在这里插入图片描述

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

源端口号(16位) 目的端口号(16位)
序号(32位)
确认序号(32位)
首部长度(4位) 保留(6位) URG ACK PSH RST SYN FIN 窗口大小(16位)
校验和(16位) 紧急指针(16位)
选项和填充(如果有)
数据区

标志位 该位置1后的意义
URG 首部中的紧急指针字段有效
ACK 首部中的确认序号有效
PSH 尽快将这个报文交给应用层(推送数据)
RST 连接复位
SYN 发送连接,同步序号
FIN 终止连接

3-2 IP、ARP数据包交互过程

ARP表成员结构体定义:
在这里插入图片描述

ARP和IP为两个相互独立协议,都属于网络层上协议,都依赖以太网帧来传输自身协议数据包。
ARP地址解析协议:提供了一种动态地址解析机制(请求和应答,MAC和IP地址地址映射),APR协议在没找到MAC地址的时候是不会发送数据的,因此这些数据会暂时存储在ARP表项中。
IP层输入实现功能:1.字段的校验2.地址的比较(转发还是接收)3.数据报分片重组4.将数据递交至上层协议。
IP层输出实现的功能:1.填充数据报首部2.选择数据报的发送路径3.对数据报进行分片处理4.发送数据报。
在这里插入图片描述

3-3 TCPIP线程

LwIP 在操作系统的环境下,LwIP 内核是作为操作系统的一个线程运行的,在协议栈初始化的时候就会创建tcpip_thread 线程。
•消息结构
tcpip_thread 线程是通过tcpip_msg 描述消息的,tcpip_thread 线程接收到消息后,根据消息的类型进行不同的处理。
在这里插入图片描述

其中tcpip_msg_type 枚举类型定义了系统中可能出现的消息的类型。
在这里插入图片描述

消息结构msg 字段是一个共用体,其中定义了各种消息类型的具体内容,每种类型的消息对应了共用体中的一个字段,其中注册与删除事件的消息使用了同一个tmo 字段。LwIP 中的API 相关的消息内容很多,不适合直接放在tcpip_msg 中,所以LwIP 用一个api_msg 结构体来描述API 消息,在tcpip_msg 中只存放指向api_msg 结构体的指针。
•数据包消息
数据格式:
在这里插入图片描述

数据包的消息,是通过tcpip_input()函数对消息进行构造并且投递的,数据包消息运作如下图所示。
在这里插入图片描述

•API消息
数据格式:
在这里插入图片描述

api_msg 只包含3 个字段,描述连接信息的conn、内核返回的执行结果err、还有msg,msg 是一个共用体,根据不一样 的API 接口使用不一样的数据结构,简单来说用户使用NETCONN API 接口的时候,LwIP 会将对应API 函数与参数构造成消息传递(TCPIP_APIMSG()函数进行投递消息)到tcpip_thread 线程中,然后根据对应的API 函数执行对应的操作。
总的来说,用户的应用线程与内核也是相互独立的,依赖操作系统的 IPC 通信机制进行数据交互与同步(邮箱、信号量等),LwIP 提供上层NETCONN API 接口,会自动帮我们处理这些事情,只需要我们根据API 接口传递正确的参数接口。
在这里插入图片描述

注意,将LWIP_TCPIP_CORE_LOCKING 宏定义设置为1, 则无需操作系统邮箱与信号量的参与,直接在用户线程中通过回调函数调用对应的处理。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/67529
推荐阅读
相关标签
  

闽ICP备14008679号