我最近正在学习Linux内核(版本4.4)中的TCP / IP实现,并对接受队列感到非常困惑。我知道struct inet_connection_sock
中有一个队列,称为接受队列:
struct inet_connection_sock {
...
/* @icsk_accept_queue: FIFO of established children */
struct request_sock_queue icsk_accept_queue;
...
}
其中有一个qlen
成员,我认为它用于指示队列的长度。
struct request_sock_queue {
...
/* length of the queue? */
atomic_t qlen;
...
};
这是我想知道的:当LISTEN套接字接收到SYN数据包时,在函数tcp_conn_request
中,将调用inet_csk_reqsk_queue_hash_add
将新创建的NEW_SYN_RECV袜子放入ehash表(不是{{1 }})
icsk_accept_queue
但是在此函数中,调用inet_csk_reqsk_queue_added
以递增void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
unsigned long timeout)
{
reqsk_queue_hash_req(req, timeout); // add to ehash table
inet_csk_reqsk_queue_added(sk); // increment icsk_accept_queue.qlen
}
。我的问题是,为什么icsk_accept_queue.qlen
没有插入任何内容,为什么增加qlen
?不是icsk_accept_queue的长度吗?
此外,tcp_conn_request
叫inet_csk_reqsk_queue_add
,将快速打开的袜子(如果启用)添加到icsk_accept_queue
:
icsk_accept_queue
但是此函数最终使struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
struct request_sock *req,
struct sock *child)
{
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
spin_lock(&queue->rskq_lock);
if (unlikely(sk->sk_state != TCP_LISTEN)) {
inet_child_forget(sk, req, child);
child = NULL;
} else {
req->sk = child;
req->dl_next = NULL;
if (queue->rskq_accept_head == NULL)
queue->rskq_accept_head = req;
else
queue->rskq_accept_tail->dl_next = req;
queue->rskq_accept_tail = req;
sk_acceptq_added(sk); // increment sk.sk_ack_backlog
}
spin_unlock(&queue->rskq_lock);
return child;
}
(通过调用sk_acceptq_added
)而不是sk.sk_ack_backlog
递增。为什么不呢?