trash748 发表于 2014-02-02 18:01

为什么socket.listen的backlog参数比实际少1

在2.6中backlog最少是1,在2.7之后,backlog最少是0,设为0时,socket等待队列却能容纳1个连接,这是为什么?

变形金刚四 发表于 2014-02-02 22:21

帮顶                           

ilex 发表于 2014-02-03 01:47

LZ应该知道backlog是干啥用的哦(如不清楚可百度)

LWIP的代码如下,linux的没查,

lpcb->backlog = (backlog ? backlog : 1);

trash748 发表于 2014-02-03 12:13

回复 3# ilex


    backlog为0的时候,等待队列可以有1个客户连接,backlog为1的时候,等待队列可以容纳2个连接,这和backlog作用不符呀?python2.6的时候backlog最低为1,python2.7就改成最低为0了,2.7的changelog里面也没找到相关的详细说明

ilex 发表于 2014-02-05 00:15

说实话,从没看过linux的内核代码,

特意查了一下linux有关backlog的代码,我猜和下面有关:

A、处理收到的connect请求:
static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
                             int addr_len, int flags)
{

line1067              if (unix_recvq_full(other)) {
                               校验backlog失败,报错;
                     }
}

B:校验队列是否超过backlog
static inline int unix_recvq_full(struct sock const *sk)
{
        return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog;
}
——这个函数看起来是比较sk_receive_queue队列的长度和socket设置的backlog值,用的是>而不是>=

C:sk_receive_queue队列在如下增长:
line 1156
        /* take ten and and send info to listening sock */
        spin_lock(&other->sk_receive_queue.lock);
        __skb_queue_tail(&other->sk_receive_queue, skb);
        spin_unlock(&other->sk_receive_queue.lock);
        unix_state_unlock(other);
        other->sk_data_ready(other, 0);
        sock_put(other);
        return 0;

3、上面两处行号,是在af_unix.c文件中。
   也就是说:先看队列满(超)了没,再入队列。
   当设置为1时,
   收到第一个sync,看到队列有0个,此时没超,入队列,队列长==1。
   再收到一个sync,看到队列有1个,此时没超,入队列,队列长==2。

4、对于设置backlog==0,就先不讨论了,可以试一下设置为1时:c/c++是什么效果,和python是否一样的效果?
   看起来和python无关,倒是操作系统/TCPIP相关的问题吧?



linux文件太多,不知道从哪看起,根据感觉在sourcinsight瞎猜的,说错了别笑话。。。

ilex 发表于 2014-02-05 00:48

好像找错了代码,感觉和下面几个函数有关:
static inline void sk_acceptq_added(struct sock *sk)
{
        sk->sk_ack_backlog++;
}

static inline int sk_acceptq_is_full(struct sock *sk)
{
        return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
}


太晚了,以后再找。

ilex 发表于 2014-02-06 07:56

刚看了一下,猜测和上面2个函数有关,

/*
*        Process an incoming packet for SYN_RECV sockets represented
*        as a request_sock.
*/

struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                           struct request_sock *req,
                           struct request_sock **prev)
{

}
tcp_check_req【先】调用
                child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb,
                                                               req, NULL);
在->syn_recv_sock里面调用sk_acceptq_is_full(struct sock *sk),检查是否超过了backlog

tcp_check_req【再】调用inet_csk_reqsk_queue_add(sk, req, child);,把SYN挂到链表中。

gaojl0728 发表于 2014-02-08 22:26

这个问题跟python 本身没关系, 是linux内核实现的问题,就是楼上说的原因,是sk_acceptq_is_full的问题,
sk->sk_max_ack_backlog就是listen设置的backlog值,sk->sk_ack_backlog是当前backlog长度,
注意他用的是大于比较,就是说等于的时候他不认为是full的,还会继续接受链接,因此用netstat看到的最大连接数永远是backlog+1。

其实这是linux内核的小bug,不过没什么大问题。
页: [1]
查看完整版本: 为什么socket.listen的backlog参数比实际少1