套接字之listen系统调用

对于面向连接的socket,需要会用监听连接的到来,并且使用backlog参数来限制连接数量;具体backlog限制的内容,请参考本博另外一篇文章,本文结尾提供链接地址;

 1 /*
 2  *    Perform a listen. Basically, we allow the protocol to do anything
 3  *    necessary for a listen, and if that works, we mark the socket as
 4  *    ready for listening.
 5  */
 6 
 7 SYSCALL_DEFINE2(listen, int, fd, int, backlog)
 8 {
 9     struct socket *sock;
10     int err, fput_needed;
11     int somaxconn;
12 
13     /* 查找socket结构 */
14     sock = sockfd_lookup_light(fd, &err, &fput_needed);
15     if (sock) {
16         somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
17 
18         /* backlog不能超过设置值 */
19         if ((unsigned int)backlog > somaxconn)
20             backlog = somaxconn;
21 
22         /* 安全模块检查 */
23         err = security_socket_listen(sock, backlog);
24         if (!err)
25             /* 调用对应类型的listen函数,只有SOCK_STREAM支持listen */
26             err = sock->ops->listen(sock, backlog);
27 
28         fput_light(sock->file, fput_needed);
29     }
30     return err;
31 }

 

inet_listen、数对socket类型,连接状态等进行基本的校验,如果已经处于listen状态,则只会调整backlog的值,如果尚未处于listen状态,则调用传输层的listen实现函数进行针对的listen操作;

 1 /*
 2  *    Move a socket into listening state.
 3  */
 4 int inet_listen(struct socket *sock, int backlog)
 5 {
 6     struct sock *sk = sock->sk;
 7     unsigned char old_state;
 8     int err;
 9 
10     lock_sock(sk);
11 
12     err = -EINVAL;
13 
14     /* 检查socket状态和类型,仅支持SOCK_STREAM */
15     if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
16         goto out;
17 
18     /* 记录连接当前状态 */
19     old_state = sk->sk_state;
20 
21     /* 检查连接状态,需为close或者listen */
22     if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN)))
23         goto out;
24 
25     /* Really, if the socket is already in listen state
26      * we can only allow the backlog to be adjusted.
27      */
28     /* 如果尚未listen过 */
29     if (old_state != TCP_LISTEN) {
30         /* Enable TFO w/o requiring TCP_FASTOPEN socket option.
31          * Note that only TCP sockets (SOCK_STREAM) will reach here.
32          * Also fastopen backlog may already been set via the option
33          * because the socket was in TCP_LISTEN state previously but
34          * was shutdown() rather than close().
35          */
36         /* TFO相关*/
37         if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) &&
38             (sysctl_tcp_fastopen & TFO_SERVER_ENABLE) &&
39             !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) {
40             fastopen_queue_tune(sk, backlog);
41             tcp_fastopen_init_key_once(true);
42         }
43 
44         /* 开始监听 */
45         err = inet_csk_listen_start(sk, backlog);
46         if (err)
47             goto out;
48     }
49 
50     /* 设置backlog,包括已经listen过,调整backlog */
51     sk->sk_max_ack_backlog = backlog;
52     err = 0;
53 
54 out:
55     release_sock(sk);
56     return err;
57 }
58 EXPORT_SYMBOL(inet_listen);

 

其中tcp层对于listen的实现,实际上也是调用了inet_csk_get_port函数,与bind()系统调用在tcp层的调用函数一致,listen的时候,如果发现尚未绑定端口,则自动选择端口绑定,已经绑定端口,则进行相关检查;具体请参考bind()系统调用的tcp层实现;请阅读<TCP层bind系统调用的实现分析>;

 

关于TCP的listen函数和backlog参数说明,请移步以下文章<TCP之listen&backlog>;

posted @ 2017-10-02 02:05  AlexAlex  阅读(925)  评论(0编辑  收藏  举报