码迷,mamicode.com
首页 > 其他好文 > 详细

lwip socket探秘之accept

时间:2015-01-07 00:32:33      阅读:392      评论:0      收藏:0      [点我收藏+]

标签:

一个基本的socket建立顺序是
Server端:
  • socket()
  • bind()
  • listen()
  • accept()
  • recv()
Client端:
  • socket()
  • connect()
  • send()
 
本文着重介绍Server端的accept()过程。
 
上一篇我们已经分析了listen()过程,listen()过程新建了pcb并把它放到了tcp_listen_pcbs这个链表里。
接下来,Client端通过Server绑定的地址和端口号(通过bind绑定),给Server发包。Server收到了Client过来的TCP包后,如何记住这个Client,并且接下来会做什么呢?这些就是这篇小文分析的内容。
 
首先Server端TCP层接到了Client来的TCP segment。我们从lwip中TCP层rx的入口开始讲起。
tcp_input()是TCP层rx数据的入口,如下面代码段红色注释部分所示。
注意传进来的参数p,虽然这是TCP层入口,但它内部的p->payload是没有剥离ip头的,原因就是,TCP层处理socket时,是需要remote端的ip的。这一点从tcp_input()函数内部就能看出来。
代码段如下:
  1 /**
  2 * The initial input processing of TCP. It verifies the TCP header, demultiplexes
  3 * the segment between the PCBs and passes it on to tcp_process(), which implements
  4 * the TCP finite state machine. This function is called by the IP layer (in
  5 * ip_input()).
  6 *
  7 * @param p received TCP segment to process (p->payload pointing to the IP header)
  8 * @param inp network interface on which this segment was received
  9 */
 10 void
 11 tcp_input(struct pbuf *p, struct netif *inp)
 12 {
 13   struct tcp_pcb *pcb, *prev;
 14   struct tcp_pcb_listen *lpcb;
 15   u8_t hdrlen;
 16   err_t err;
 17 
 18   PERF_START;
 19 
 20   TCP_STATS_INC(tcp.recv);
 21   snmp_inc_tcpinsegs();
 22 
 23   iphdr = p->payload; // 得到了IP header
 24   tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); // 得到了TCP header
 25 
 26 ............
 27 
 28   /* Convert fields in TCP header to host byte order. */
 29   tcphdr->src = ntohs(tcphdr->src); // 把tcp header的一些内容从网络字节序转成主机字节序。可以猜测ip header已经在ip层被转过了。
 30   tcphdr->dest = ntohs(tcphdr->dest);
 31   seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
 32   ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
 33   tcphdr->wnd = ntohs(tcphdr->wnd);
 34 
 35 ..................
 36 
 37 //下面出现了3个pcb链表,分别是tcp_active_pcbs、tcp_tw_pcbs和tcp_listen_pcbs。
 38   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
 39     LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
 40     LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
 41     LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
 42     if (pcb->remote_port == tcphdr->src &&
 43        pcb->local_port == tcphdr->dest &&
 44        ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
 45        ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
 46 
 47       /* Move this PCB to the front of the list so that subsequent
 48          lookups will be faster (we exploit locality in TCP segment
 49          arrivals). */
 50       LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
 51       if (prev != NULL) {
 52         prev->next = pcb->next;
 53         pcb->next = tcp_active_pcbs;
 54         tcp_active_pcbs = pcb;
 55       }
 56       LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
 57       break;
 58     }
 59     prev = pcb;
 60   }
 61 
 62   if (pcb == NULL) {
 63     /* If it did not go to an active connection, we check the connections
 64        in the TIME-WAIT state. */
 65     for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
 66       LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
 67       if (pcb->remote_port == tcphdr->src &&
 68          pcb->local_port == tcphdr->dest &&
 69          ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
 70          ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
 71         /* We don‘t really care enough to move this PCB to the front
 72            of the list since we are not very likely to receive that
 73            many segments for connections in TIME-WAIT. */
 74         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
 75         tcp_timewait_input(pcb);
 76         pbuf_free(p);
 77         return;
 78       }
 79     }
 80 
 81 //我们暂时只关心tcp_listen_pcbs这个链表。这个链表包含了所有处在listen状态的pcb。一个listen状态的pcb是什么时候把自己注册进tcp_listen_pcbs这个链表的?这个待会讲到。
 82   /* Finally, if we still did not get a match, we check all PCBs that
 83      are LISTENing for incoming connections. */
 84     prev = NULL;
 85     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
 86       if ((ip_addr_isany(&(lpcb->local_ip)) || // 如果pcb->local_ip是0或者NULL,意味着接收任何ip的连接请求
 87         ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&  // 或者pcb->local_ip和接收到的tcp segment的ip地址一致,并且pcb->local_port和接收到的tcp segment的port号也一致,认为找到了之前注册的、并且是remote client发过来的这个tcp segment的目标的pcb。
 88         lpcb->local_port == tcphdr->dest) {
 89         /* Move this PCB to the front of the list so that subsequent
 90            lookups will be faster (we exploit locality in TCP segment
 91            arrivals). */
 92         if (prev != NULL) {
 93           ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
 94                 /* our successor is the remainder of the listening list */
 95           lpcb->next = tcp_listen_pcbs.listen_pcbs;
 96                 /* put this listening pcb at the head of the listening list */
 97           tcp_listen_pcbs.listen_pcbs = lpcb;
 98         }
 99      
100         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
101         tcp_listen_input(lpcb); // 得到server正在listen状态的pcb后,用刚收到的remote tcp segment更新pcb,马上会分析这个函数
102         pbuf_free(p);
103         return;
104       }
105       prev = (struct tcp_pcb *)lpcb;
106     }
107   }
 
tcp_listen_input()如下:
 1 /**
 2 * Called by tcp_input() when a segment arrives for a listening
 3 * connection (from tcp_input()).
 4 *
 5 * @param pcb the tcp_pcb_listen for which a segment arrived
 6 * @return ERR_OK if the segment was processed
 7 *         another err_t on error
 8 *
 9 * @note the return value is not (yet?) used in tcp_input()
10 * @note the segment which arrived is saved in global variables, therefore only the pcb
11 *       involved is passed as a parameter to this function
12 */
13 static err_t
14 tcp_listen_input(struct tcp_pcb_listen *pcb)
15 {
16   struct tcp_pcb *npcb;
17   err_t rc;
18 
19   /* In the LISTEN state, we check for incoming SYN segments,
20      creates a new PCB, and responds with a SYN|ACK. */
21   if (flags & TCP_ACK) {
22     /* For incoming segments with the ACK flag set, respond with a
23        RST. */
24     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
25     tcp_rst(ackno + 1, seqno + tcplen,
26       &(iphdr->dest), &(iphdr->src),
27       tcphdr->dest, tcphdr->src);
28   } else if (flags & TCP_SYN) {
29     LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
30 #if TCP_LISTEN_BACKLOG
31     if (pcb->accepts_pending >= pcb->backlog) {
32       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
33       return ERR_ABRT;
34     }
35 #endif /* TCP_LISTEN_BACKLOG */
36     npcb = tcp_alloc(pcb->prio); // allocate一个新的pcb,待会会放入active pcb链表
37     /* If a new PCB could not be created (probably due to lack of memory),
38        we don‘t do anything, but rely on the sender will retransmit the
39        SYN at a time when we have more memory available. */
40     if (npcb == NULL) {
41       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
42       TCP_STATS_INC(tcp.memerr);
43       return ERR_MEM;
44     }
45 #if TCP_LISTEN_BACKLOG
46     pcb->accepts_pending++;
47 #endif /* TCP_LISTEN_BACKLOG */
48     /* Set up the new PCB. */
49     ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); // pcb里存好server端自己的ip
50     npcb->local_port = pcb->local_port; // pcb里存好server端自己的port号
51     ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); // pcb里指定client端的ip
52     npcb->remote_port = tcphdr->src; // pcb里指定client端的port号
53     npcb->state = SYN_RCVD; // pcb的状态变成了SYN_RCVD
54     npcb->rcv_nxt = seqno + 1;
55     npcb->rcv_ann_right_edge = npcb->rcv_nxt;
56     npcb->snd_wnd = tcphdr->wnd;
57     npcb->ssthresh = npcb->snd_wnd;
58     npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
59     npcb->callback_arg = pcb->callback_arg;
60 #if LWIP_CALLBACK_API
61     npcb->accept = pcb->accept;
62 #endif /* LWIP_CALLBACK_API */
63     /* inherit socket options */
64     npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);
65     /* Register the new PCB so that we can begin receiving segments
66        for it. */
67     TCP_REG(&tcp_active_pcbs, npcb); // 把新pcb加入active pcbs链表,以后这个pcb专门为server端与remote ip对应的这个client端之间的通信服务
68 
69     /* Parse any options in the SYN. */
70     tcp_parseopt(npcb);
71 #if TCP_CALCULATE_EFF_SEND_MSS
72     npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
73 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
74 
75     snmp_inc_tcppassiveopens();
76 
77     /* Send a SYN|ACK together with the MSS option. */
78     rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS   // tx一个SYN|ACK
79 #if LWIP_TCP_TIMESTAMPS
80       /* and maybe include the TIMESTAMP option */
81      | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0)
82 #endif
83       );
84     if (rc != ERR_OK) {
85       tcp_abandon(npcb, 0);
86       return rc;
87     }
88     return tcp_output(npcb);
89   }
90   return ERR_OK;
91 }

 

至此,产生了一个新pcb,这个pcb处在SYN_RCVD状态。这个pcb被加入了active pcbs链表。
如果刚才的client又发送了tcp segment过来,那么接收的流程又跟上面讲的有所不同。还是从tcp_input开始分析:
 1 void
 2 tcp_input(struct pbuf *p, struct netif *inp)
 3 {
 4   struct tcp_pcb *pcb, *prev;
 5   struct tcp_pcb_listen *lpcb;
 6   u8_t hdrlen;
 7   err_t err;
 8 
 9   PERF_START;
10 
11   TCP_STATS_INC(tcp.recv);
12   snmp_inc_tcpinsegs();
13 
14   iphdr = p->payload; // 得到了IP header
15   tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); // 得到了TCP header
16 
17 ............
18 
19   /* Convert fields in TCP header to host byte order. */
20   tcphdr->src = ntohs(tcphdr->src); // 把tcp header的一些内容从网络字节序转成主机字节序。可以猜测ip header已经在ip层被转过了。
21   tcphdr->dest = ntohs(tcphdr->dest);
22   seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
23   ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
24   tcphdr->wnd = ntohs(tcphdr->wnd);
25 
26 ..................
27 
28 //下面出现了3个pcb链表,分别是tcp_active_pcbs、tcp_tw_pcbs和tcp_listen_pcbs。
29 // 这一次,tcp segment对应的client-server专属pcb能够在 tcp_active_pcbs链表里找到。
30   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
31     LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
32     LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
33     LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
34     if (pcb->remote_port == tcphdr->src && // 这个tcp segment对应的client和server信息都能和某个pcb一致,则找到了这个pcb
35        pcb->local_port == tcphdr->dest &&
36        ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
37        ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
38 
39       /* Move this PCB to the front of the list so that subsequent
40          lookups will be faster (we exploit locality in TCP segment
41          arrivals). */
42       LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
43       if (prev != NULL) {
44         prev->next = pcb->next;
45         pcb->next = tcp_active_pcbs;
46         tcp_active_pcbs = pcb;
47       }
48       LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
49       break;
50     }
51     prev = pcb;
52   }
53 
54 .............
55 
56   if (pcb != NULL) {
57        err = tcp_process(pcb);
58   }

 

tcp_process():
 1 static err_t
 2 tcp_process(struct tcp_pcb *pcb)
 3 {
 4 ..............
 5   case SYN_RCVD:
 6     if (flags & TCP_ACK) {
 7       /* expected ACK number? */
 8       if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
 9         u16_t old_cwnd;
10         pcb->state = ESTABLISHED;
11         LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
12 #if LWIP_CALLBACK_API
13         LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
14 #endif
15         /* Call the accept function. */
16         TCP_EVENT_ACCEPT(pcb, ERR_OK, err); // 这里会调到accept_function函数
17         if (err != ERR_OK) {
18           /* If the accept function returns with an error, we abort
19            * the connection. */
20           tcp_abort(pcb);
21           return ERR_ABRT;
22         }
23         old_cwnd = pcb->cwnd;
24         /* If there was any data contained within this ACK,
25          * we‘d better pass it on to the application as well. */
26         tcp_receive(pcb);
27 
28         /* Prevent ACK for SYN to generate a sent event */
29         if (pcb->acked != 0) {
30           pcb->acked--;
31         }
32 
33         pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
34 
35         if (recv_flags & TF_GOT_FIN) {
36           tcp_ack_now(pcb);
37           pcb->state = CLOSE_WAIT;
38         }
39       }
40       /* incorrect ACK number */
41       else {
42         /* send RST */
43         tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
44                 tcphdr->dest, tcphdr->src);
45       }
46     } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
47       /* Looks like another copy of the SYN - retransmit our SYN-ACK */
48       tcp_rexmit(pcb);
49     }
50     break;
51 ....................
52 }
 1 /**
 2 * Accept callback function for TCP netconns.
 3 * Allocates a new netconn and posts that to conn->acceptmbox.
 4 *
 5 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 6 */
 7 // 注意accept_function的参数是
 8 // arg:server端负责listen的那个sock的sock->conn,
 9 // newpcb:listen到tcp segment后为特定的client-server创建的pcb
10 // err:err
11 static err_t
12 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
13 {
14   struct netconn *newconn;
15   struct netconn *conn;
16 
17 #if API_MSG_DEBUG
18 #if TCP_DEBUG
19   tcp_debug_print_state(newpcb->state);
20 #endif /* TCP_DEBUG */
21 #endif /* API_MSG_DEBUG */
22   conn = (struct netconn *)arg;
23 
24   LWIP_ERROR("accept_function: invalid conn->acceptmbox",
25              conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);
26 
27   /* We have to set the callback here even though
28    * the new socket is unknown. conn->socket is marked as -1. */
29   newconn = netconn_alloc(conn->type, conn->callback); // 新建一个netconn
30   if (newconn == NULL) {
31     return ERR_MEM;
32   }
33   newconn->pcb.tcp = newpcb;
34   setup_tcp(newconn); // 这个函数很重要,我们要记住它把newconn和newpcb绑定起来了
35   newconn->err = err;
36 
37   if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { // 把newconn丢到了旧conn(即负责listen的pcb的conn)的acceptmbox这个mailbox上
38     /* When returning != ERR_OK, the connection is aborted in tcp_process(),
39        so do nothing here! */
40     newconn->pcb.tcp = NULL;
41     netconn_free(newconn);
42     return ERR_MEM;
43   } else {
44     /* Register event with callback */
45     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
46   }
47 
48   return ERR_OK;
49 }

 

现在我们已知一个新的newconn产生了,并且它放在负责listen的pcb的conn的acceptmbox里。那么谁来取走这个newconn呢?
就是lwip_accept()函数。
lwip_accept()函数就是用户使用socket过程中调用的accept()。
 1 /* Below this, the well-known socket functions are implemented.
 2 * Use google.com or opengroup.org to get a good description :-)
 3 *
 4 * Exceptions are documented!
 5 */
 6 
 7 int
 8 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) // 这里的s是负责listen的socket
 9 {
10   struct lwip_socket *sock, *nsock;
11   struct netconn *newconn;
12   struct ip_addr naddr;
13   u16_t port;
14   int newsock;
15   struct sockaddr_in sin;
16   err_t err;
17 
18   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
19   sock = get_socket(s); // 从用户可见的int型socket得到协议栈自己维护的socket descriptor
20   if (!sock)
21     return -1;
22 
23   if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) {
24     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
25     sock_set_errno(sock, EWOULDBLOCK);
26     return -1;
27   }
28 
29   newconn = netconn_accept(sock->conn);  // 传入的是listen socket指向的conn
30 ..................
31 }

 

我们先来看一下netconn_accept函数:
 1 /**
 2 * Accept a new connection on a TCP listening netconn.
 3 *
 4 * @param conn the TCP listen netconn
 5 * @return the newly accepted netconn or NULL on timeout
 6 */
 7 struct netconn *
 8 netconn_accept(struct netconn *conn)
 9 {
10   struct netconn *newconn;
11 
12 .............
13 
14 #if LWIP_SO_RCVTIMEO
15   if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
16     newconn = NULL;
17   } else
18 #else
19   sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); // 这里从listen socket->conn的acceptmbox取出1个conn,当然就是socket用户在调用listen()后,listen()通过accept_function()函数放入的新conn,这是和listen socket->conn不同的新conn,这里名字是newconn
20 #endif /* LWIP_SO_RCVTIMEO*/
21 ..................
22 
23   return newconn;
24 }

 

所以,netconn_accept取出了client端连接server后server为这一对peer生成的newconn。
我们接着回到lwip_accept()函数:
 1 /* Below this, the well-known socket functions are implemented.
 2 * Use google.com or opengroup.org to get a good description :-)
 3 *
 4 * Exceptions are documented!
 5 */
 6 
 7 int
 8 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) // 这里的s是负责listen的socket
 9 {
10 .................
11   newconn = netconn_accept(sock->conn);  // 传入的是listen socket指向的conn
12   if (!newconn) {
13     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));
14     sock_set_errno(sock, err_to_errno(sock->conn->err));
15     return -1;
16   }
17 
18   /* get the IP address and port of the remote host */
19   err = netconn_peer(newconn, &naddr, &port); // 从newconn里得到client端ip addr和port号,实际是从newconn绑定的pcb里获得
20   if (err != ERR_OK) {
21     netconn_delete(newconn);
22     sock_set_errno(sock, err_to_errno(err));
23     return -1;
24   }
25 
26   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
27    * not be NULL if addr is valid.
28    */
29   if (NULL != addr) { // 如果实参addr地址不是NULL,就把client端的ip地址和port写入addr指向的地址,作为这个函数的返回值之一。但是很多时候这个addr参数用户都会设置为NULL,不需要这个信息。
30     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
31     memset(&sin, 0, sizeof(sin));
32     sin.sin_len = sizeof(sin);
33     sin.sin_family = AF_INET;
34     sin.sin_port = htons(port);
35     sin.sin_addr.s_addr = naddr.addr;
36 
37     if (*addrlen > sizeof(sin))
38       *addrlen = sizeof(sin);
39 
40     MEMCPY(addr, &sin, *addrlen);
41   }
42 
43   newsock = alloc_socket(newconn); // 对于一个client和server的peer,现在有了新的pcb、新的conn,还需要一个新的socket给用户用!并且这个函数还把newconn和socket绑定起来了,从新socket能得到newconn。
44   if (newsock == -1) {
45     netconn_delete(newconn);
46     sock_set_errno(sock, ENFILE);
47     return -1;
48   }
49   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
50   newconn->callback = event_callback;
51   nsock = &sockets[newsock];
52   LWIP_ASSERT("invalid socket pointer", nsock != NULL);
53 
54   sys_sem_wait(socksem);
55   /* See event_callback: If data comes in right away after an accept, even
56    * though the server task might not have created a new socket yet.
57    * In that case, newconn->socket is counted down (newconn->socket--),
58    * so nsock->rcvevent is >= 1 here!
59    */
60   nsock->rcvevent += -1 - newconn->socket;
61   newconn->socket = newsock; // 从newconn能找到new socket
62   sys_sem_signal(socksem);
63 
64   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
65   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
66   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
67 
68   sock_set_errno(sock, 0);
69   return newsock;
70 }
lwip_accept()函数返回了一个new socket,这个socket从listen socket而来,是server专为listen到的client准备的一个socket,可以认为是为这一对通路单独服务的server端socket。我们先把它叫做专属socket。
 
 accept()过程结束,返回的socket用于接下来的recv()。
 
 
 

lwip socket探秘之accept

标签:

原文地址:http://www.cnblogs.com/codingfun/p/4184187.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!