LwIP 核心流程总结
主要内容参照9. LwIP一探究竟 — [野火]LwIP应用开发实战指南—基于野火STM32 文档,整理出来自用。
一、网卡接收数据流程
数据从硬件到 LwIP 内核的传递,通过 “中断触发 + 线程通信” 实现,核心是解耦接收与处理。
- 硬件触发:网卡接收数据后,生成接收中断。
- 中断响应:中断服务函数释放信号量,通知 “网卡接收线程” 处理数据。
- 消息封装:接收线程将数据封装为
TCPIP_MSG_INPKT
类型消息(含数据包pbuf
、网卡netif
、处理函数ethernet_input
)。 - 消息投递:通过
tcpip_inpkt()
函数,将消息投递到 LwIP 内核邮箱tcpip_mbox
。 - 内核处理:
tcpip_thread
线程从邮箱获取消息,调用ethernet_input()
函数:- 若为 ARP 包:直接更新 ARP 缓存表,不进入 IP 层;
- 若为 IP 包:递交给 IP 层进一步处理。
二、内核超时处理
LwIP 通过软件超时链表管理所有超时事件(如 ARP 缓存过期、TCP 重传超时),依赖用户提供的时基。
1. 核心数据结构
结构 / 变量 | 作用 |
---|---|
sys_timeo 结构体 | 单个超时事件:含超时时间time 、回调函数h 、函数参数arg 、链表指针next 。 |
next_timeout | 超时链表头指针,指向第一个待处理的超时事件。 |
lwip_cyclic_timers | 内置周期性超时事件数组(如 TCP 定时器 250ms、ARP 定时器 1000ms)。 |
2. 关键流程
- 注册超时事件:
- 用户调用
sys_timeout(msecs, handler, arg)
,计算绝对超时时间(当前时间 +msecs
); - 调用
sys_timeout_abs()
从内存池申请sys_timeo
,按超时时间升序插入链表。
- 用户调用
- 周期性事件维护:
- LwIP 初始化时(
sys_timeouts_init()
),将lwip_cyclic_timers
中事件注册到链表; - 事件超时执行回调后,通过
sys_timeout_abs()
重新注册,实现 “循环触发”。
- LwIP 初始化时(
- 超时检查与处理:
- 裸机:用户周期性调用
sys_check_timeouts()
,检查链表头事件是否超时,超时则执行回调并删除。 - 操作系统:
tcpip_thread
通过tcpip_timeouts_mbox_fetch()
,阻塞等待邮箱消息时同步检查超时,超时则调用sys_check_timeouts()
。
- 裸机:用户周期性调用
三、tcpip_thread 内核线程
LwIP 内核的 “主线程”,负责接收消息、处理超时、调度核心逻辑。
1. 核心逻辑
while (1) {// 1. 阻塞等待邮箱消息,同时处理超时事件TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); if (msg == NULL) continue;// 2. 按消息类型处理tcpip_thread_handle_msg(msg);
}
2. 消息处理(tcpip_thread_handle_msg)
根据tcpip_msg
的类型,分发到对应处理逻辑:
消息类型 | 处理动作 |
---|---|
TCPIP_MSG_API | 执行用户 API 对应的回调函数(如lwip_netconn_do_bind )。 |
TCPIP_MSG_INPKT | 调用ethernet_input() ,处理网卡接收的数据包(ARP/IP 包分流)。 |
TCPIP_MSG_TIMEOUT | 注册超时事件(调用sys_timeout() )。 |
TCPIP_MSG_UNTIMEOUT | 删除超时事件(调用sys_untimeout() )。 |
TCPIP_MSG_CALLBACK | 执行用户注册的回调函数。 |
四、LwIP 消息机制
用户线程 / 网卡接收线程与tcpip_thread
的通信桥梁,核心是tcpip_msg
结构体与tcpip_mbox
邮箱。
1. 核心消息结构(tcpip_msg)
struct tcpip_msg {enum tcpip_msg_type type; // 消息类型union {struct { tcpip_callback_fn function; void* msg; } api_msg; // API消息struct { struct pbuf *p; struct netif *netif; } inp; // 数据包消息struct { u32_t msecs; sys_timeout_handler h; } tmo; // 超时消息// 其他消息类型...} msg;
};
2. 两类关键消息
消息类型 | 发起方 | 核心作用 | 投递函数 |
---|---|---|---|
数据包消息 | 网卡接收线程 | 传递网卡接收的数据包到内核 | tcpip_inpkt() |
API 消息 | 用户应用线程 | 传递用户 API 调用(如netconn_bind )到内核 | netconn_apimsg() |
3. 优化配置(LWIP_TCPIP_CORE_LOCKING)
- 当宏定义
LWIP_TCPIP_CORE_LOCKING=1
时:
无需通过邮箱传递 API 消息,用户线程直接加锁调用内核函数(减少线程调度开销),是 LwIP 推荐配置。 - 当
LWIP_TCPIP_CORE_LOCKING=0
时:
API 消息需通过邮箱投递,用户线程需等待信号量同步(开销较高)。
核心交互关系图
[网卡硬件] → 接收中断 → [接收线程] → 封装数据包消息 → 投递到tcpip_mbox → [tcpip_thread]↓
[用户应用线程] → 封装API消息 → 投递到tcpip_mbox → [tcpip_thread] → 调用内核函数↓
[超时链表] → tcpip_timeouts_mbox_fetch()检查 → 超时则执行回调