【文章內(nèi)容簡介】
tcp 的 原型: int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 可以看到這里的 socket 類型參數(shù) s,實(shí)際上是個(gè) int型 在這個(gè)函數(shù)中的第一個(gè)函數(shù)調(diào)用是 sock = get_socket(s)。 這里的 sock 變量類型是 lwip_socket,定義如下: /** Contains all internal pointers and states used for a socket */ struct lwip_socket { /** sockets currently are built on conns, each socket has one conn */ struct conn *conn。 /** data that was left from the previous read */ struct buf *lastdata。 /** offset in the data that was left from the previous read */ u16_t lastoffset。 /** number of times data was received, set by event_callback(), tested by the receive and select functions */ u16_t rcvevent。 /** number of times data was received, set by event_callback(), tested by select */ u16_t sendevent。 /** socket flags (currently, only used for O_NONBLOCK) */ u16_t flags。 /** last error that occurred on this socket */ int err。 }。 好,這個(gè)結(jié)構(gòu)先不管它,接著看下 get_socket 函數(shù)的實(shí)現(xiàn)【也是在 src\api\】,在這里我們看到這樣一條語句 sock = amp。sockets[s]。很明顯,返回值也是這個(gè) sock,它是根據(jù)傳進(jìn)來的序列號(hào)在 sockets數(shù)組中找到對(duì)應(yīng)的元素并返回該元素的地址。好了,那么這個(gè) sockets 數(shù)組是在哪里被賦值了這些元素的呢? 進(jìn)行到這里似乎應(yīng)該從標(biāo)準(zhǔn)的 socket編程的開始,也就是 socket函數(shù)講起,那我們就順便看一下。它對(duì)應(yīng)的實(shí)際實(shí)現(xiàn)是下面這個(gè)函數(shù) Int lwip_socket(int domain, int type, int protocol)【 src\api\】 19 這個(gè)函數(shù)根據(jù)不同的協(xié)議類型,也就是函數(shù)中的 type 參數(shù),創(chuàng)建了一個(gè) conn結(jié)構(gòu)體的指針,接著就是用這個(gè)指針作為參數(shù)調(diào)用了 alloc_socket 函數(shù),下面具體看下這個(gè)函數(shù)的實(shí)現(xiàn) static int alloc_socket(struct conn *newconn) { int i。 /* Protect socket array */ sys_sem_wait(socksem)。 /* allocate a new socket identifier */ for (i = 0。 i NUM_SOCKETS。 ++i) { if (!sockets[i].conn) { sockets[i].conn = newconn。 sockets[i].lastdata = NULL。 sockets[i].lastoffset = 0。 sockets[i].rcvevent = 0。 sockets[i].sendevent = 1。 /* TCP send buf is empty */ sockets[i].flags = 0。 sockets[i].err = 0。 sys_sem_signal(socksem)。 return i。 } } sys_sem_signal(socksem)。 return 1。 } 對(duì)了,就是這個(gè)時(shí)候?qū)θ肿兞?sockets 數(shù)組的元素賦值的。 既然都來到這 里了,那就順便看下 conn 結(jié)構(gòu)的情況吧。它的學(xué)名叫 conn descriptor /** A conn descriptor */ struct conn { /** type of the conn (TCP, UDP or RAW) */ enum conn_type type。 /** current state of the conn */ enum conn_state state。 /** the lwIP internal protocol control block */ union { struct ip_pcb *ip。 struct tcp_pcb *tcp。 struct udp_pcb *udp。 struct raw_pcb *raw。 } pcb。 /** the last error this conn had */ 20 err_t err。 /** sem that is used to synchroneously execute functions in the core context */ sys_sem_t op_pleted。 /** mbox where received packets are stored until they are fetched by the conn application thread (can grow quite big) */ sys_mbox_t recvmbox。 /** mbox where new connections are stored until processed by the application thread */ sys_mbox_t acceptmbox。 /** only used for socket layer */ int socket。 if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening conns) */ int recv_timeout。 endif /* LWIP_SO_RCVTIMEO */ if LWIP_SO_RCVBUF /** maximum amount of bytes queued in recvmbox */ int recv_bufsize。 endif /* LWIP_SO_RCVBUF */ u16_t recv_avail。 /** TCP: when data passed to conn_write doesn39。t fit into the send buffer, this temporarily stores the message. */ struct api_msg_msg *write_msg。 /** TCP: when data passed to conn_write doesn39。t fit into the send buffer, this temporarily stores how much is already sent. */ int write_offset。 if LWIP_TCPIP_CORE_LOCKING /** TCP: when data passed to conn_write doesn39。t fit into the send buffer, this temporarily stores whether to wake up the original application task if data couldn39。t be sent in the first try. */ u8_t write_delayed。 endif /* LWIP_TCPIP_CORE_LOCKING */ /** A callback function that is informed about events for this conn */ conn_callback callback。 }?!?src\include\lwip\】 到此,對(duì)這個(gè)結(jié)構(gòu)都有些什么,做了一個(gè)大概的了解。 下面以 SOCK_STREAM 類型為例,看下 conn 的 new 過程: 在 lwip_socket 函數(shù)中有 case SOCK_DGRAM: 21 conn = conn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP, event_callback)。 define conn_new_with_callback(t, c) conn_new_with_proto_and_callback(t, 0, c) 簡略實(shí)現(xiàn)如下: struct conn* conn_new_with_proto_and_callback(enum conn_type t, u8_t proto, conn_callback callback) { struct conn *conn。 struct api_msg msg。 conn = conn_alloc(t, callback)。 if (conn != NULL ) { = do_newconn。 = proto。 = conn。 TCPIP_APIMSG(amp。msg)。 } return conn。 } 主要就看 TCPIP_APIMSG 了,這個(gè)宏有兩個(gè)定義,一個(gè)是 LWIP_TCPIP_CORE_LOCKING的,一個(gè)非 locking的。分別分析這兩個(gè)不同類型的函數(shù) * Call the lower part of a conn_* function * This function has exclusive access to lwIP core code by locking it * before the function is called. err_t tcpip_apimsg_lock(struct api_msg *apimsg)【這個(gè)是可以 locking的】 { LOCK_TCPIP_CORE()。 apimsgfunction(amp。(apimsgmsg))。 UNLOCK_TCPIP_CORE()。 return ERR_OK。 } * Call the lower part of a conn_* function * This function is then running in the thread context * of tcpip_thread and has exclusive access to lwIP core code. err_t tcpip_apimsg(struct api_msg *apimsg)【此為非 locking的】 { struct tcpip_msg msg。 22 if (mbox != SYS_MBOX_NULL) { = TCPIP_MSG_API。 = apimsg。 sys_mbox_post(mbox, amp。msg)。 sys_arch_sem_wait(apimsgop_pleted, 0)。 return ERR_OK。 } return ERR_VAL。 } 其實(shí),功能都是一樣的,都是要對(duì) apimsgfunction 函數(shù)的調(diào)用。只是途徑不一樣而已。看看它們的功能說明就知道了。這么來 說 apimsgfunction 的調(diào)用很重要了。從 conn_new_with_proto_and_callback 函數(shù)的實(shí)現(xiàn),可以知道這個(gè) function 就是 do_newconn Void do_newconn(struct api_msg_msg *msg) { if(msgconn == NULL) { pcb_new(msg)。 } /* Else? This new c