该参数的作用似乎是限制服务器在高负载下处理当前请求和少量排队挂起请求所需的合理时间内保留在队列中的传入连接请求数量。以下是我遇到的一个很好的段落,它为这个参数提供了一些背景上下文...
最后,listen 的参数告诉套接字库,在拒绝外部连接之前,我们希望将多达5个连接请求(正常最大值)排队等待处理。如果其余代码编写正确,那应该足够了。
https://docs.python.org/3/howto/sockets.html#creating-a-socket
文档中早些时候的文字建议客户端应该反复与服务器进行通信,以避免在首次请求时建立长时间的请求队列...
当connect
完成后,套接字s
可以用于发送页面文本的请求。同一个套接字将读取回复,然后被销毁。没错,被销毁了。客户端套接字通常仅用于一次交换(或一小组连续的交换)。
当您开始学习使用套接字进行网络编程时,建议阅读相关的HowTo指南。它确实聚焦了一些关于此主题的大局观。至于服务器套接字如何管理请求队列的实现细节,那是另外一个故事,可能很有趣。我想这种设计的动机更有说服力,如果没有这种设计,拒绝服务攻击的门槛将非常非常低。
关于为什么最小值为0而非1的原因,我们应该记住0仍然是一个有效值,意味着不排队任何请求。这基本上是说让没有请求队列,如果服务器套接字当前正在服务于一个连接,就直接拒绝连接。在这种情况下,始终要牢记当前正在服务的活动连接的重要性,这也是队列首先感兴趣的唯一原因。
这带我们来到关于“首选值”的下一个问题。这是一个设计决策,你想排队请求还是不想?如果是这样,你可以根据预期流量和已知硬件资源选择你认为合理的值。我想在选择一个值时没有任何公式可循。这让我想知道请求本身有多轻量级,以至于在服务器上排队任何东西都会受到惩罚。
更新
我希望证实用户207421的评论,并查找了Python源代码。不幸的是,在sockets.py源代码中找不到这种详细信息,而在哈希值530f506处的socketmodule.c#L3351-L3382中可以找到。
这些评论非常有启发性,我将在此直接复制源代码,并突出说明这里的澄清评论,这些评论非常有启发性...
我们尝试选择一个默认的backlog(等待连接队列)大小,以避免常见工作负载时的连接中断,但不会太高以限制资源使用。
和
如果指定了backlog,则必须至少为0(如果低于0,则设置为0);它指定系统在拒绝新连接之前允许的未接受连接数。如果未指定,则选择一个合理的默认值。
static PyObject *
sock_listen(PySocketSockObject *s, PyObject *args)
{
int backlog = Py_MIN(SOMAXCONN, 128);
int res;
if (!PyArg_ParseTuple(args, "|i:listen", &backlog))
return NULL;
Py_BEGIN_ALLOW_THREADS
if (backlog < 0)
backlog = 0;
res = listen(s->sock_fd, backlog);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(listen_doc,
"listen([backlog])\n\
\n\
Enable a server to accept connections. If backlog is specified, it must be\n\
at least 0 (if it is lower, it is set to 0); it specifies the number of\n\
unaccepted connections that the system will allow before refusing new\n\
connections. If not specified, a default reasonable value is chosen.");
继续深入外部依赖项,我追踪了来自socketmodule的以下源代码...
res = listen(s->sock_fd, backlog);
这个源代码位于
socket.h和
socket.c,以Linux作为具体平台背景进行讨论。
#define SOMAXCONN 128
extern int __sys_listen(int fd, int backlog);
在手册页中可以找到更多信息
http://man7.org/linux/man-pages/man2/listen.2.html
int listen(int sockfd, int backlog);
相应的文档字符串
listen()
将由sockfd
引用的套接字标记为被动套接字,即将用于使用accept
(2)接受传入的连接请求的套接字。
sockfd
参数是一个文件描述符,它引用了一种类型为SOCK_STREAM
或SOCK_SEQPACKET
的套接字。
backlog
参数定义了sockfd
的挂起连接队列可以增长的最大长度。如果队列已满,则客户端可能会收到带有ECONNREFUSED
指示的错误,或者如果底层协议支持重传,则该请求可能会被忽略,以便稍后重新尝试连接成功。
另外一个source标识内核负责挂起队列。
该函数的第二个参数
backlog指定内核应为此套接字排队的最大连接数。他们简要地介绍了未接受/排队的连接如何在backlog中分区(链接源中包含有用的图表)。要理解
backlog参数,我们必须意识到,对于给定的侦听套接字,内核维护两个队列:一个不完整的连接队列,其中包含每个SYN的条目,这些SYN来自服务器正在等待完成TCP三次握手的客户端。这些套接字处于
SYN_RCVD
状态(图2.4)。一个已完成的连接队列,其中包含每个与完成TCP三次握手的客户端的条目。这些套接字处于
ESTABLISHED
状态(图2.4)。这两个队列如下图所示:当在不完整队列上创建条目时,将从侦听套接字复制参数到新创建的连接。连接创建机制是完全自动的;服务器进程没有参与。