日期:2014-05-16 浏览次数:20858 次
几个问题
了解以下几个问题的同学可以直接忽略下文:
1、listen
库函数主要做了什么?
2、
什么是最大并发连接请求数?
3、什么是等待连接队列?
socket
监听相对还是比较简单的,先看下应用程序代码:
listen( server_sockfd, 5) ;?
其中,第一个参数
server_sockfd为服务端
socket所对应的文件描述符,第二个参数5
代表监听socket
能处理的最大并发连接请求数,在2.6.26
内核中,该值为
256
;
listen
库函数调用的主要工作可以分为以下几步:
1
、根据
socket文件描述符找到内核中对应的
socket结构体变量;这个过程在《socket地址绑定
》
一文中描述过,这里不再重述;
2
、设置
socket的状态并初始化等待连接队列;
3
、将
socket放入listen
哈希表中;
listen
调用代码跟踪
下面是
listen库函数对应的内核处理函数:
asmlinkage long sys_listen(int fd, int backlog) { struct socket *sock; int err, fput_needed; int somaxconn; // 根据文件描述符取得内核中的socket sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { // 根据系统中的设置调整参数backlog somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; if ((unsigned)backlog > somaxconn) backlog = somaxconn; err = security_socket_listen(sock, backlog); // 调用相应协议簇的listen函数 if (!err) err = sock->ops->listen(sock, backlog); fput_light(sock->file, fput_needed); } return err; }?
根据《创建socket
》
一文的介绍,例子中,这里sock->ops->
listen(sock, backlog)
实际上调用的是
net/ipv4/Af_inet.c:inet_listen()
函数:
int inet_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; unsigned char old_state; int err; lock_sock(sk); err = -EINVAL; // 1 这里首先检查socket的状态和类型,如果状态或类型不正确,返回出错信息 if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) goto out; old_state = sk->sk_state; // 2 这里检查sock的状态是否是TCP_CLOSE或TCP_LISTEN,如果不是,返回出错信息 if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) goto out; /* Really, if the socket is already in listen state * we can only allow the backlog to be adjusted. */ // 3 当sock的状态不是TCP_LISTEN时,做监听相关的初始化 if (old_state != TCP_LISTEN) { err = inet_csk_listen_start(sk, backlog); if (err) goto out; } // 4 设置sock的最大并发连接请求数 sk->sk_max_ack_backlog = backlog; err = 0; out: release_sock(sk); return err; }?
上面的代码中,有点值得注意的是,当 sock 状态已经是 TCP_LISTEN 时,也可以继续调用 listen() 库函数,其作用是设置