lwip socket探秘之listen


一个基本的socket建立顺序是
Server端:
  • socket()
  • bind()
  • listen()
  • accept()
  • recv()
Client端:
  • socket()
  • connect()
  • send()
 
本文着重介绍Server端的listen()过程。
 
用户使用socket,调用listen()时,实际调用的是lwip里的lwip_listen()。代码如下
 1 /**  2 * Set a socket into listen mode.  3 * The socket may not have been used for another connection previously.  4 *  5 * @param s the socket to set to listening mode  6 * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1)  7 * @return 0 on success, non-zero on failure  8 */
 9 int
10 lwip_listen(int s, int backlog) 11 { 12   struct lwip_socket *sock; 13  err_t err; 14 ............. 15   sock = get_socket(s); // 根据socket号(面向用户的socket标识)得到lwip内部的socket descriptor
16   if (!sock) 17     return -1; 18 ............... 19   err = netconn_listen_with_backlog(sock->conn, backlog); // 接下来看这个函数
20 ............... 21   return 0; 22 }

netconn_listen_with_backlog本身内容很少,主要是向下一连串调用:

netconn_listen_with_backlog
     =>do_listen
          =>tcp_listen
               =>tcp_listen_with_backlog
 
tcp_listen_with_backlog这个函数才是真正做了重要工作的地方。
 1 /**  2 * Set the state of the connection to be LISTEN, which means that it  3 * is able to accept incoming connections. The protocol control block  4 * is reallocated in order to consume less memory. Setting the  5 * connection to LISTEN is an irreversible process.  6 *  7 * @param pcb the original tcp_pcb  8 * @param backlog the incoming connections queue limit  9 * @return tcp_pcb used for listening, consumes less memory. 10 * 11 * @note The original tcp_pcb is freed. This function therefore has to be 12 * called like this: 13 * tpcb = tcp_listen(tpcb); 14 */
15 struct tcp_pcb *
16 tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) 17 { 18   struct tcp_pcb_listen *lpcb; 19 
20  LWIP_UNUSED_ARG(backlog); 21   LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); 22 
23   /* already listening? */
24   if (pcb->state == LISTEN) { 25     return pcb; 26  } 27   lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); // 新建了一个pcb,后面会把原来的pcb free掉
28   if (lpcb == NULL) { 29     return NULL; 30  } 31   lpcb->callback_arg = pcb->callback_arg; // 新pcb继承旧pcb的一些内容
32   lpcb->local_port = pcb->local_port; 33   lpcb->state = LISTEN; // 因为用户调用了listen(),所以这个新pcb的状态是LISTEN
34   lpcb->so_options = pcb->so_options; 35   lpcb->so_options |= SOF_ACCEPTCONN; 36   lpcb->ttl = pcb->ttl; 37   lpcb->tos = pcb->tos; 38   ip_addr_set(&lpcb->local_ip, &pcb->local_ip); 39   TCP_RMV(&tcp_bound_pcbs, pcb); 40   memp_free(MEMP_TCP_PCB, pcb); // free掉旧的pcb
41 #if LWIP_CALLBACK_API
42   lpcb->accept = tcp_accept_null; 43 #endif /* LWIP_CALLBACK_API */
44 #if TCP_LISTEN_BACKLOG
45   lpcb->accepts_pending = 0; 46   lpcb->backlog = (backlog ? backlog : 1); 47 #endif /* TCP_LISTEN_BACKLOG */
48   TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); // 把新pcb挂到tcp_listen_pcbs这个链表里
49   return (struct tcp_pcb *)lpcb; 50 }
注意阅读函数上方的注释,这些注释简要的介绍了函数的作用,写的都非常有用。
tcp_listen_with_backlog这个函数主要是重新开辟了一个pcb代替旧的pcb(出于节省空间的考虑),将新pcb的状态设置为LISTEN,并将其挂在lwip里的tcp_listen_pcbs这个链表里。
 
 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM