分享

lwip socket探秘之listen

 心不留意外尘 2016-07-11

 http://www.cnblogs.com/codingfun/p/4186343.html

2014
一个基本的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这个链表里。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多