listen()忽略了backlog参数?

28

我有以下问题:

我有 sockfd = socket(AF_INET, SOCK_STREAM, 0)

之后我设置并绑定了套接字(比如用sockfd.sin_port = htons(666)),然后立即执行:

listen(sockfd, 3);

sleep(50); // for test purposes

我正在睡眠50秒以测试backlog参数,但似乎被忽略了,因为我可以在666端口上建立超过3次的连接。

*:我的意思是,对于客户端发送的每个第N个SYN(n> 3)放置在监听队列中,我都会收到一个syn/ack,而不是被丢弃。出了什么问题?我已经阅读了listen(2)和tcp(7)的man页面,并发现:

TCP套接字上backlog参数的行为在Linux 2.2中发生了变化。 现在,它指定等待接受的完全建立的套接字的队列长度,而不是不完整的连接请求的数量。 不完整套接字队列的最大长度可以使用/proc/sys/net/ipv4/tcp_max_syn_backlog来设置。启用syncookies后,没有逻辑最大长度,该设置将被忽略。 更多信息请参见tcp(7)。

但即使使用sysctl -w sys.net.ipv4.tcp_max_syn_backlog=2sysctl -w net.ipv4.tcp_syncookies=0,我仍然得到相同的结果!我一定是错过了什么,或者完全误解了listen()的backlog目的。

2个回答

42
< p > listen()函数的backlog参数仅供参考。

POSIX说

backlog参数提供了一个提示,供实现限制套接字监听队列中未完成连接的数量。

Linux内核的当前版本将其四舍五入至最接近的二次幂,最小值为16。 相关代码位于reqsk_queue_alloc()中。


1
你知道为什么要将最小值设置为16而不是1吗? - gojomo
1
这并不完全正确。函数reqsk_queue_alloc()计算表分配的值,但在函数inet_listen()中,backlog的值被分配给sk->sk_max_ack_backlog,并且此值在此处使用:static inline int sk_acceptq_is_full(struct sock *sk) { return sk->sk_ack_backlog > sk->sk_max_ack_backlog; } - Nikolai
我正在使用Ubuntu。如果我没有误解你的意思,当我将backlog设置为1时,它会被舍入为2(即下一个最高的2的幂)。但是,即使我使用backlog 1调用listen,我仍然可以成功地创建100个连接到套接字。 - satoru
1
@Marisha,请尝试在搜索中添加内核关键字。 :) - Nikolai
1
@amn:Linux确实使用POSIX语义作为指导,特别是在套接字接口的情况下。不过,我的回答还包括了实际的Linux行为,并提供了实现它的源代码链接,我认为这在Linux特定的上下文中相当明确地回答了问题。 - caf
显示剩余5条评论

4

同一来源称,基于伯克利的操作系统将后台处理队列长度乘以1.5,并为其提供一个队列,但做出这样的决定的原因“已经不可考”。该新的来源链接将您指向特定页面,在该页面上有这样的说明:(来源:http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA108&ots=Kq9FQogkTr&dq=berkeley%20listen%20backlog%20ack&pg=PA106#v=onepage&q=berkeley%20listen%20backlog%20ack&f=false) - gpcz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接