LwIP的netconn API流程

 

api_lib.c,其中包含了所有的netconn API实现,应用若使用netconn,只需要包含api.h即可。

api_msg.c,其中为与tcpip主线程进行消息交互的消息处理。

以netconn_new为例,api.h中定义如下

1 #define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL)

会发送一个api_msg给tcpip主线程,api_msg.c中定义如下

 1 struct netconn*
 2 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
 3 {
 4   struct netconn *conn;
 5   struct api_msg msg;
 6 
 7   conn = netconn_alloc(t, callback);
 8   if (conn != NULL) {
 9     msg.function = do_newconn;
10     msg.msg.msg.n.proto = proto;
11     msg.msg.conn = conn;
12     if (TCPIP_APIMSG(&msg) != ERR_OK) {
19       sys_sem_free(&conn->op_completed);
20       sys_mbox_free(&conn->recvmbox);
21       memp_free(MEMP_NETCONN, conn);
22       return NULL;
23     }
24   }
25   return conn;
26 }

其中,tcpip.h中定义如下

1 #define TCPIP_APIMSG(m)       tcpip_apimsg(m)

tcpip.c中定义如下,实际,会将消息发送给tcpip主线程的邮箱mbox,且一直等待完成(通过等待信号量op_completed实现,在do_xxx函数中会调用TCPIP_APIMSG_ACK(msg),该函数就是释放该信号量)。

 1 err_t
 2 tcpip_apimsg(struct api_msg *apimsg)
 3 {
 4   struct tcpip_msg msg;
10   if (sys_mbox_valid(&mbox)) {
11     msg.type = TCPIP_MSG_API;
12     msg.msg.apimsg = apimsg;
13     sys_mbox_post(&mbox, &msg);
14     sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
15     return apimsg->msg.err;
16   }
17   return ERR_VAL;
18 }

tcpip主线程中,会一直查询邮箱mbox。第8行,一直查询mbox,第14行,执行消息的函数,这里其实执行的是do_newconn

 1 static void
 2 tcpip_thread(void *arg)
 3 {
 4   struct tcpip_msg *msg;
 5 
 6   while (1) {                          /* MAIN Loop */
 7     /* wait for a message, timeouts are processed while waiting */
 8     sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
 9     LOCK_TCPIP_CORE();
10     switch (msg->type) {
11 #if LWIP_NETCONN
12     case TCPIP_MSG_API:
13       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
14       msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
15       break;
16 #endif /* LWIP_NETCONN */
17 
18 #if !LWIP_TCPIP_CORE_LOCKING_INPUT
19     case TCPIP_MSG_INPKT:
20       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
21 #if LWIP_ETHERNET
22       if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
23         ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
24       } else
25 #endif /* LWIP_ETHERNET */
26       {
27         ip_input(msg->msg.inp.p, msg->msg.inp.netif);
28       }
29       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
30       break;
31 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
32 
33     case TCPIP_MSG_CALLBACK:
34       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
35       msg->msg.cb.function(msg->msg.cb.ctx);
36       memp_free(MEMP_TCPIP_MSG_API, msg);
37       break;
38 
39     default:
40       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
41       LWIP_ASSERT("tcpip_thread: invalid message", 0);
42       break;
43     }
44   }
45 }

api_msg.c中的do_newconn,执行pcb_new()函数,创建pcb协议控制块,在其中,会根据是udp还是tcp等,创建相应的pcb。

1 void
2 do_newconn(struct api_msg_msg *msg)
3 {
4   msg->err = ERR_OK;
5   if(msg->conn->pcb.tcp == NULL) {
6     pcb_new(msg);
7   }

 

下图为netconn_new()函数对应的两个线程中的函数,及中间沟通的邮箱(消息队列mbox)。只有两个线程,所有函数都在其中一个线程的上下文中执行。

LwIP的netconn API流程

 

 

下图为接收数据的过程,涉及3个线程:接收线程,tcpip主线程,和应用线程。使用了两个消息队列用于传递消息。有3个线程,所有函数都在其中一个线程的上下文中执行。

LwIP的netconn API流程

 

对于tcpip.c

tcpip_init()会创建mbox邮箱。

tcpip_thread()会接收mbox,并处理。

tcpip_input()是所有netif的input函数,在其中创建msg,然后发送到mbox。

 

LwIP的netconn API流程

上一篇:Photoshop制作柔美的橙红色树林婚片


下一篇:在C#MVC项目中使用邮箱(验证码验证)