多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
对于每种类型的消息,LwIP内核都必须有一个产生与之对应的消息函数,在产生该类型的消息后就将其投递到系统邮箱tcpip\_mbox中,这样子tcpip\_thread线程就会从邮箱中得到消息并且处理,从而能使内核完美运作,从图 9‑1中我们可以很直观看到对应数据包的消息,是通过tcpip\_input()函数对消息进行构造并且投递的,但是真正执行这些操作的函数是tcpip\_inpkt(),其源码具体见代码清单 9‑10。 ``` 1 err_t 2 tcpip_input(struct pbuf *p, struct netif *inp) 3 { 4 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) 5 { 6 return tcpip_inpkt(p, inp, ethernet_input); (1) 7 } 8 } 9 10 err_t 11 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 12 { 13 struct tcpip_msg *msg; 14 15 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 16 17 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); (2) 18 if (msg == NULL) 19 { 20 return ERR_MEM; 21 } 22 23 msg->type = TCPIP_MSG_INPKT; 24 msg->msg.inp.p = p; 25 msg->msg.inp.netif = inp; 26 msg->msg.inp.input_fn = input_fn; (3) 27 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) (4) 28 { 29 memp_free(MEMP_TCPIP_MSG_INPKT, msg); (5) 30 return ERR_MEM; 31 } 32 return ERR_OK; 33 } ``` (1):调用tcpip_inpkt()函数将ethernet_input()函数作为结构体的一部分传递给内核,然后内核接收到这个数据包就调用该函数。 (2):申请存放消息的内存空间。 (3):构造消息,消息的类型是数据包消息,初始化消息结构中msg共用体的inp字段,p指向数据包,网卡就是对应的网卡,处理的函数就是我们熟悉的ethernet_input()函数。 (4):构造消息完成,就调用sys_mbox_trypost进行投递消息,这其实就是对操作系统的API简单封装,如果投递成功则返回ERR_OK。 (5):如果投递失败,就释放对应的消息结构空间。 总的来说,万变不离其宗,无论是裸机编程还是操作系统,都是通过ethernet_input()函数去处理接收到的数据包,只不过操作系统通过线程与线程间数据通信,使用了消息进行传递,这样子能使接收线程与内核线程互不干扰,相互独立开,在操作系统环境下,接收线程只负责接收数据包、构造消息并且完成投递消息即可,这样子处理完又能接收下一个数据包,这样子的效率更加高效,而内核根据这些消息做对应处理即可。 其运作示意图具体见图 9 3。 ![](https://box.kancloud.cn/42fbfd501317c205a9d0de7efd2c6bbf_758x391.png)