内核listen的backlog和简单的三次握手分析

1. 背景:

        前面通过抓包分析了listen backlog对全连接和半连接的影响,本文将从内核源码(kernel 2.6.32)上简单了解下服务端三次握手的过程以及backlog在中间所起的作用。

2. 三次握手:

2.1 服务端监听:

        在system_call后,通过fd号获取相应的socket,及对backlog最值进行限制后,然后进入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;
	if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
		goto out;

	old_state = sk->sk_state;
	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.
	 */
	if (old_state != TCP_LISTEN) {
		err = inet_csk_listen_start(sk, backlog);
		if (err)
			goto out;
	}
	sk->sk_max_ack_backlog = backlog;
	err = 0;

out:
	release_sock(sk);
	return err;
}
        这函数进行简单的状态校验,然后进入inet_csk_listen_start初始化监听的套接字,最后注意,sk->sk_max_ack_backlog修改为backlog大小,这个变量后续将作用于sk_acceptq_is_full函数,用于判断半连接队列,因此backlog对于半连接是有作用的。

static inline int sk_acceptq_is_full(struct sock *sk)
{
	return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
}
int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
{
	struct inet_sock *inet = inet_sk(sk);
	struct inet_connection_sock *icsk = inet_csk(sk);
	int rc = reqsk_queue_alloc(&icsk->icsk_accept_queue, nr_table_entries);

	if (rc != 0)
		return rc;

	/* 初始化backlog为0,回到上层后赋值,见前文。  */
	sk->sk_max_ack_backlog = 0;
	sk->sk_ack_backlog = 0;
	inet_csk_delack_init(sk);

	/* There is race window here: we announce ourselves listening,
	 * but this transition is still not validated by get_port().
	 * It is OK, because this socket enters to hash table only
	 * after validation is complete.
	 */
	/* 检查端口是否被占用。  */
	sk->sk_state = TCP_LISTEN;
	if (!sk->sk_prot->get_port(sk, inet->num)) {
		inet->sport = htons(inet->num);

		sk_dst_reset(sk);
		sk->sk_prot->hash(sk);

		return 0;
	}

	sk->sk_state = TCP_CLOSE;
	__reqsk_queue_destroy(&icsk->icsk_accept_queue);
	return -EADDRINUSE;
}
        初始化主要初始化了backlog,在上层会被重新赋值为backlog,还检查监听的端口是否被占用。此外还要注意函数reqsk_queue_alloc函数,真正初始化了一个listen_sock。listen_sock数据结果见下面代码,主要开辟了一个哈希桶记录半连接的状态。
int reqsk_queue_alloc(struct request_sock_queue *queue, unsigned int nr_table_entries)
{
    size_t lopt_size = sizeof(struct listen_sock);
    /** struct listen_sock - listen state
     *
     * @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs
     */
    /* 
     struct listen_sock {
     /* 哈希大小。  */
     u8 max_qlen_l
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值