lwip socket探秘之accept


一個基本的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()。
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM