🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
有的同学可能会发现,前面讲解的超时处理根本是不需要我们用户去考虑的,为什么还有讲解呢,其实不是这样子的,学习讲究的是一个循序渐进的过程,本书讲解的东西自然有其要讲解的道理,LwIP实现了超时处理,那么无论我们的开发平台是否使用操作系统,都可以对其进行超时检查并且去处理,lwip中以下两个函数可以实现对超时的处理: void sys\_check\_timeouts(void):这是用于裸机的函数,用户需要在裸机应用程序中周期性调用该函数,每次调用的时候LwIP都会检查超时链表上第一个sys\_timeo结构体是否到期,如果没有到期,直接退出该函数,否则,执行sys\_timeo结构体中对应的超时回调函数,并从链表上删除它,然后继续检查下一个sys\_timeo结构体,直到sys\_timeo结构体没有超时才退出。 tcpip\_timeouts\_mbox\_fetch(sys\_mbox\_t \*mbox, void \*\*msg):这个函数在操作系统的线程中循环调用,主要是等待tcpip\_mbox消息,是可阻塞的,如果在等待tcpip\_mbox的过程中发生超时事件,则会同时执行超时事件处理,即调用超时回调函数。LwIP是这样子处理的,如果已经发生超时,LwIP就会内部调用sys\_check\_timeouts()函数去检查超时的sys\_timeo结构体并调用其对应的回调函数,如果没有发生超时,那就一直等待消息,其等待的时间为下一个超时时间的时间,一举两得。 LwIP中tcpip线程就是靠这种方法,即处理了上层及底层的tcpip\_mbox消息,同时处理了所有需要超时处理的事件。具体见代码清单 9‑6。 ``` 1 #define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg) 2 3 static void 4 tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 5 { 6 u32_t sleeptime, res; 7 8 again: 9 LWIP_ASSERT_CORE_LOCKED(); 10 11 sleeptime = sys_timeouts_sleeptime(); (1) 12 if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) 13 { 14 UNLOCK_TCPIP_CORE(); 15 sys_arch_mbox_fetch(mbox, msg, 0); (2) 16 LOCK_TCPIP_CORE(); 17 return; 18 } 19 else if (sleeptime == 0) 20 { 21 sys_check_timeouts(); (3) 22 goto again; 23 } 24 25 UNLOCK_TCPIP_CORE(); 26 res = sys_arch_mbox_fetch(mbox, msg, sleeptime); (4) 27 LOCK_TCPIP_CORE(); 28 if (res == SYS_ARCH_TIMEOUT) 29 { 30 sys_check_timeouts(); 31 goto again; 32 } 33 } ``` (1):调用sys_timeouts_sleeptime()函数得到距离事件超时的时间并保存在sleeptime变量中。 (2):如果sleeptime为SYS_TIMEOUTS_SLEEPTIME_INFINITE,表示当前系统无超时事件,那只需一直等待mbox消息即可,所以调用sys_arch_mbox_fetch()函数进行等待消息,等待时间是一直等待。 (3):如果sleeptime为0表示已经发生超时了,那就调用sys_check_timeouts()去检查一下到底是哪个事件发生超时并且去处理其超时回调函数。 (4):对于其他时间,LwIP就在等待tcpip_mbox的消息的同时就去处理超时事件,等待tcpip_mbox的消息的时间为sleeptime,然后在时间到达的时候就处理超时事件。如果接收到消息,并且超时时间还没到,那就去处理tcpip_mbox的消息,然后再回来重新计算等待时间sleeptime,如此反复,这样子既不会错过tcpip_mbox的消息,也不会错过超时的事件。