网络中的listen

Posted 为了维护世界和平_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络中的listen相关的知识,希望对你有一定的参考价值。

listen主要工作

        申请和初始化接收队列,全连接接收队列和半接收队列

int __sys_listen(int fd, int backlog)

	struct socket *sock;
	int err, fput_needed;
	int somaxconn;
	//根据fd查找socket内核对象
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (sock) 
		//获取内核somaxconn参数;net.core.somaxconn,与backlog 取其中小的
		somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
		if ((unsigned int)backlog > somaxconn)
			backlog = somaxconn;

		err = security_socket_listen(sock, backlog);
		if (!err)//调用协议栈初始化listen
			err = sock->ops->listen(sock, backlog);

		fput_light(sock->file, fput_needed);
	
	return err;

backlog与系统里的net.core.somaxconn内核参数选择一个小的

sock->ops->listen函数

int inet_listen(struct socket *sock, int backlog)

	struct sock *sk = sock->sk;
	unsigned char old_state;
	int err, tcp_fastopen;

    //如果是监听状态,则允许backlog参数调整,设置全连接队列长度
	WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
	

	//不是listen状态,进入监听
	if (old_state != TCP_LISTEN) 

		tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
		if ((tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) &&
		    (tcp_fastopen & TFO_SERVER_ENABLE) &&
		    !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) 
			fastopen_queue_tune(sk, backlog);
			tcp_fastopen_init_key_once(sock_net(sk));
		
		//开始监听
		err = inet_csk_listen_start(sk, backlog);
		if (err)
			goto out;
		tcp_call_bpf(sk, BPF_SOCK_OPS_TCP_LISTEN_CB, 0, NULL);
	
	err = 0;

out:
	release_sock(sk);
	return err;

全连接队列结构体

struct inet_connection_sock 
	/* inet_sock has to be the first member! */
	struct inet_sock	  icsk_inet;
	struct request_sock_queue icsk_accept_queue;
    ...



struct request_sock_queue 
	spinlock_t		rskq_lock;
	u8			rskq_defer_accept;

	u32			synflood_warned;
	atomic_t		qlen;
	atomic_t		young;
	//全连接队列
	struct request_sock	*rskq_accept_head;
	struct request_sock	*rskq_accept_tail;

	struct fastopen_queue	fastopenq;  /* Check max_qlen != 0 to determine
					     * if TFO is enabled.
					     */
;

int inet_csk_listen_start(struct sock *sk, int backlog)

	struct inet_connection_sock *icsk = inet_csk(sk);
	struct inet_sock *inet = inet_sk(sk);
	int err = -EADDRINUSE;

	//icsk_accept_queue接收队列
	//接收队列内核对象初始化
	reqsk_queue_alloc(&icsk->icsk_accept_queue);

	sk->sk_ack_backlog = 0;
	inet_csk_delack_init(sk);

	inet_sk_state_store(sk, TCP_LISTEN);
	if (!sk->sk_prot->get_port(sk, inet->inet_num)) 
		inet->inet_sport = htons(inet->inet_num);

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

		if (likely(!err))
			return 0;
	

	inet_sk_set_state(sk, TCP_CLOSE);
	return err;


static inline void fastopen_queue_tune(struct sock *sk, int backlog)

	struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
	int somaxconn = READ_ONCE(sock_net(sk)->core.sysctl_somaxconn);
	//半连接队列长度
	queue->fastopenq.max_qlen = min_t(unsigned int, backlog, somaxconn);

总结:listen主要工作申请和初始化接收队列,全连接接收队列和半接收队列

全连接接收队列长度

        backlog与net.core.somaxconn之间较小的值

以上是关于网络中的listen的主要内容,如果未能解决你的问题,请参考以下文章

网络连接返回getsockopt: connection refused错误原因 及 listen

网络编程-----bind()listen()

oracle网络配置

Oracle数据库学习_Oracle监听程序LISTENER和网络服务名Tnsname

oracle的监听器listener 和 java web的监听器listener 的联系是啥?

网络运维