Python TCP 连接中的“积压”是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36594400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 18:04:38  来源:igfitidea点击:

What is "backlog" in TCP connections?

pythonsocketstcpnetwork-programmingudp

提问by Am_I_Helpful

Below, you see a python program that acts as a server listening for connection requests to port 9999:

下面,您将看到一个 Python 程序,它充当服务器,侦听端口9999 的连接请求:

# server.py 
import socket                                         
import time

# create a socket object
serversocket = socket.socket(
            socket.AF_INET, socket.SOCK_STREAM) 

# get local machine name
host = socket.gethostname()                           

port = 9999                                           

# bind to the port
serversocket.bind((host, port))                                  

# queue up to 5 requests
serversocket.listen(5)                                           

while True:
    # establish a connection
    clientsocket,addr = serversocket.accept()      

    print("Got a connection from %s" % str(addr))
    currentTime = time.ctime(time.time()) + "\r\n"
    clientsocket.send(currentTime.encode('ascii'))
    clientsocket.close()

The questions is what is the function of the parameter of socket.listen()method (i.e. 5).

问题是socket.listen()方法(即5)的参数的功能是什么。

Based on the tutorials around the internet:

基于互联网上的教程:

The backlog argument specifies the maximum number of queued connections and should be at least 0; the maximum value is system-dependent (usually 5), the minimum value is forced to 0.

backlog 参数指定排队连接的最大数量,并且应该至少为 0;最大值取决于系统(通常为 5),最小值强制为 0。

But:

但:

  1. What are these queued connections?
  2. Does it make any difference for client requests? (I mean is the server that is running with socket.listen(5)different from the server that is running with socket.listen(1)in accepting connection requests or in receiving data?)
  3. Why is the minimum value zero? Shouldn't it be at least 1?
  4. Is there a preferred value?
  5. Is this backlogdefined for TCP connections only or does it apply for UDP and other protocols too?
  1. 这些排队的连接是什么?
  2. 它对客户请求有什么影响吗?(我的意思是正在运行socket.listen(5)的服务器与socket.listen(1)在接受连接请求或接收数据时正在运行的服务器不同吗?)
  3. 为什么最小值为零?不应该是至少1吗?
  4. 有首选值吗?
  5. 这是backlog仅针对 TCP 连接定义的还是也适用于 UDP 和其他协议?

回答by Am_I_Helpful

NOTE : Answers are framed without having any background in Python, but, the questions are irrelevant to language, to be answered.

注意:答案是在没有任何 Python 背景的情况下制定的,但是,这些问题与语言无关,需要回答。

What are these queued connections?

这些排队的连接是什么?

In simple words, the backlog parameter specifies the number of pending connections the queue will hold.

简而言之,backlog 参数指定队列将保留的挂起连接数。

When multiple clients connect to the server, the server then holds the incoming requests in a queue. The clients are arranged in the queue, and the server processes their requests one by one as and when queue-member proceeds. The nature of this kind of connection is called queued connection.

当多个客户端连接到服务器时,服务器会将传入的请求保存在队列中。客户端排列在队列中,服务器在队列成员进行时一一处理它们的请求。这种连接的性质称为排队连接。

Does it make any difference for client requests? (I mean is the server that is running with socket.listen(5)different from the server that is running with socket.listen(1)in accepting connection requests or in receiving data?)

它对客户请求有什么影响吗?(我的意思是正在运行socket.listen(5)的服务器与socket.listen(1)在接受连接请求或接收数据时正在运行的服务器不同吗?)

Yes, both cases are different. The first case would allow only 5 clients to be arranged to the queue; whereas in the case of backlog=1, only 1 connection can be hold in the queue, thereby resulting in the dropping of the further connection request!

是的,两种情况是不同的。第一种情况只允许将 5 个客户端安排到队列中;而在backlog=1的情况下,队列中只能保留1个连接,从而导致进一步的连接请求被丢弃!

Why is the minimum value zero? Shouldn't it be at least 1?

为什么最小值为零?不应该至少是1吗?

I have no idea about Python, but, as per this source, in C, a backlog argument of 0 may allow the socket to accept connections, in which case the length of the listen queue may be set to an implementation-defined minimum value.

我不知道 Python,但是,根据这个来源,在 C 中,积压参数 0 可能允许套接字接受连接,在这种情况下,侦听队列的长度可以设置为实现定义的最小值。

Is there a preferred value?

有首选值吗?

This question has no well-defined answer. I'd say this depends on the nature of your application, as well as the hardware configurations and software configuration too. Again, as per the source, BackLogis silently limited to between 1 and 5, inclusive(again as per C).

这个问题没有明确的答案。我会说这取决于您的应用程序的性质,以及硬件配置和软件配置。同样,根据来源,BackLog默默地限制在 1 和 5 之间,包括(再次根据 C)。

Is this backlog defined for TCP connections only or does it apply for UDP and other protocols too?

这个积压是只为 TCP 连接定义的还是也适用于 UDP 和其他协议?

NO. Please note that there's no need to listen() or accept() for unconnected datagram sockets(UDP). This is one of the perks of using unconnected datagram sockets!

不。请注意,对于未连接的数据报套接字 (UDP),无需使用 listen() 或 accept()。这是使用未连接数据报套接字的好处之一!

But, do keep in mind, then there are TCP based datagram socket implementations (called TCPDatagramSocket) too which have backlog parameter.

但是,请记住,还有基于 TCP 的数据报套接字实现(称为 TCPDatagramSocket)也具有 backlog 参数。

回答by freakish

When TCP connection is being established the so called three-way handshake is performed. Both sides exchange some packets and once they do it this connection is called complete and it is ready to be used by the application.

在建立 TCP 连接时,将执行所谓的三向握手。双方交换一些数据包,一旦他们这样做,这个连接就被称为完成,它可以被应用程序使用。

However this three-way handshake takes some time. And during that time the connection is queued and this is the backlog. So you can set the maximum amount of incomplete parallel connections via .listen(no)call (note that according to the posix standard the value is only a hint, it may be totally ignored). If someone tries to establish a connection above backlog limit the other side will refuse it.

然而,这种三向握手需要一些时间。在那段时间里,连接排队,这是积压。因此,您可以通过.listen(no)调用设置不完整并行连接的最大数量(请注意,根据 posix 标准,该值只是一个提示,可能会被完全忽略)。如果有人试图在积压限制之上建立连接,另一方将拒绝它。

So the backlog limit is about pending connections, not established.

所以积压限制是关于挂起的连接,而不是建立。

Now higher backlog limit will be better in most cases. Note that the maximum limit is OS dependent, e.g. cat /proc/sys/net/core/somaxconngives me 128on my Ubuntu.

在大多数情况下,现在更高的积压限制会更好。请注意,最大限制取决于操作系统,例如在我的 Ubuntu 上cat /proc/sys/net/core/somaxconn给我128

回答by jxramos

The function of the parameter appears to be to limit the number of incoming connect requests a server will retain in a queue assuming it can serve the current request and the small amount of queued pending requests in a reasonable amount of time while under high load. Here's a good paragraph I came against that lends a little context around this argument...

该参数的功能似乎是限制服务器将保留在队列中的传入连接请求的数量,假设它可以在高负载下在合理的时间内为当前请求和少量排队等待请求提供服务。这是我反对的一个很好的段落,它为这个论点提供了一些背景......

Finally, the argument to listen tells the socket library that we want it to queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty.

最后,listen 的参数告诉套接字库我们希望它在拒绝外部连接之前最多排队 5 个连接请求(正常的最大值)。如果代码的其余部分编写正确,那应该足够了。

https://docs.python.org/3/howto/sockets.html#creating-a-socket

https://docs.python.org/3/howto/sockets.html#creating-a-socket

There's text earlier up in the document that suggests clients should dip in and out of a server so you don't build up a long queue of requests in the first place...

文档前面的文本建议客户端应该进出服务器,这样您就不会首先建立一个很长的请求队列......

When the connectcompletes, the socket scan be used to send in a request for the text of the page. The same socket will read the reply, and then be destroyed. That's right, destroyed. Client sockets are normally only used for one exchange (or a small set of sequential exchanges).

connect完成时,插座s可用于在页面的文本请求发送。同一个套接字会读取回复,然后被销毁。没错,毁了。客户端套接字通常仅用于一次交换(或一小组顺序交换)。

The linked HowTo guide is a must read when getting up to speed on network programming with sockets. It really brings into focus some big picture themes about it. Now how the server socket manages this queue as far as implementation details is another story, probably an interesting one. I suppose the motivation for this design is more telling, without it the barrier for inflicting a denial of service attackwould be very very low.

在使用套接字进行网络编程时,必须阅读链接的 HowTo 指南。它确实引起了一些关于它的大图主题的关注。现在服务器套接字如何管理这个队列就实现细节而言是另一回事,可能是一个有趣的故事。我想这种设计的动机更有说服力,没有它,造成拒绝服务攻击的障碍将非常低。

As far as the reason for a minimum valueof 0 vs 1, we should keep in mind that 0 is still a valid value, meaning queue up nothing. That is essentially to say let there be no request queue, just reject connections outright if the server socket is currently serving a connection. The point of a currently active connection being served should always be kept in mind in this context, it's the only reason a queue would be of interest in the first place.

至于最小值0 vs 1的原因,我们应该记住,0 仍然是一个有效值,这意味着什么都不排队。这实质上是说没有请求队列,如果服务器套接字当前正在为连接提供服务,则直接拒绝连接。在这种情况下,应始终牢记正在服务的当前活动连接的要点,这是首先对队列感兴趣的唯一原因。

This brings us to the next question regarding a preferred value. This is all a design decision, do you want to queue up requests or not? If so you may pick a value you feel is warranted based on expected traffic and known hardware resources I suppose. I doubt there's anything formulaic in picking a value. This makes me wonder how lightweight a request is in the first place that you'd face a penalty in queuing anything up on the server.

这将我们带到下一个关于首选值的问题。这完全是一个设计决定,您是否要排队请求?如果是这样,您可以根据我认为的预期流量和已知硬件资源选择一个您认为有保证的值。我怀疑在选择一个值时是否有任何公式化的东西。这让我想知道一个请求是多么轻量级,首先你会在服务器上排队任何东西时面临惩罚。



UPDATE

更新

I wanted to substantiate the comments from user207421 and went to lookup the python source. Unfortunately this level of detail is not to be found in the sockets.pysource but rather in socketmodule.c#L3351-L3382as of hash 530f506.

我想证实 user207421 的评论并去查找 python 源代码。不幸的是这种详细程度是不是在找到sockets.py源,而是在socketmodule.c#L3351-L3382哈希530f506的。

The comments are very illuminating, I'll copy the source verbatim below and single out the clarifying comments here which are pretty illuminating...

这些评论非常有启发性,我将逐字复制下面的源代码,并在这里挑选出非常有启发性的澄清评论......

We try to choose a default backlog high enough to avoid connection drops for common workloads, yet not too high to limit resource usage.

我们尝试选择足够高的默认 backlog 以避免常见工作负载的连接中断,但又不会太高以限制资源使用。

and

If backlog is specified, it must be at least 0 (if it is lower, it is set to 0); it specifies the number of unaccepted connections that the system will allow before refusing new connections. If not specified, a default reasonable value is chosen.

如果指定backlog,则必须至少为0(如果较低,则设置为0);它指定系统在拒绝新连接之前允许的未接受连接数。如果未指定,则选择默认的合理值。

/* s.listen(n) method */

static PyObject *
sock_listen(PySocketSockObject *s, PyObject *args)
{
    /* We try to choose a default backlog high enough to avoid connection drops
     * for common workloads, yet not too high to limit resource usage. */
    int backlog = Py_MIN(SOMAXCONN, 128);
    int res;

    if (!PyArg_ParseTuple(args, "|i:listen", &backlog))
        return NULL;

    Py_BEGIN_ALLOW_THREADS
    /* To avoid problems on systems that don't allow a negative backlog
     * (which doesn't make sense anyway) we force a minimum value of 0. */
    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.");

Going further down the rabbithole into the externals I trace the following source from socketmodule...

进一步深入到外部,我从 socketmodule 追踪以下来源......

 res = listen(s->sock_fd, backlog);

This source is over at socket.hand socket.cusing linux as a concrete platform backdrop for discussion purposes.

这个源在socket.hsocket.c 上结束,使用 linux 作为讨论的具体平台背景。

/* Maximum queue length specifiable by listen.  */
#define SOMAXCONN   128
extern int __sys_listen(int fd, int backlog);

There's more info to be found in the man page

在手册页中可以找到更多信息

http://man7.org/linux/man-pages/man2/listen.2.html

http://man7.org/linux/man-pages/man2/listen.2.html

int listen(int sockfd, int backlog);

And the corresponding docstring

以及相应的文档字符串

listen()marks the socket referred to by sockfdas a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).

The sockfdargument is a file descriptor that refers to a socket of type SOCK_STREAMor SOCK_SEQPACKET.

The backlogargument defines the maximum length to which the queue of pending connections for sockfdmay grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSEDor, if the underlying protocol supports retransmission, the request may be ignored so that a later reattempt at connection succeeds.

listen()将被sockfd称为被动套接字的套接字标记为被动套接字,即,使用accept(2)将其标记为将用于接受传入连接请求的套接字。

sockfd说法是指类型的套接字文件描述符SOCK_STREAMSOCK_SEQPACKET

backlog参数定义了挂起连接队列sockfd可以增长到的最大长度。如果连接请求在队列已满时到达,则客户端可能会收到错误指示,ECONNREFUSED或者,如果底层协议支持重传,则该请求可能会被忽略,以便稍后重新尝试连接成功。

One additional sourceidentifies the kernel as being responsible for the backlog queue.

另一个来源将内核标识为负责积压队列。

The second argument backlogto this function specifies the maximum number of connections the kernel should queue for this socket.

此函数的第二个参数backlog指定内核应为此套接字排队的最大连接数。

They briefly go on to relate how the unaccepted / queued connections are partitioned in the backlog (a useful figure is included on the linked source).

他们简要地继续介绍未接受/排队的连接如何在积压中进行分区(链接源中包含一个有用的数字)。

To understand the backlogargument, we must realize that for a given listening socket, the kernel maintains two queues:

An incomplete connection queue, which contains an entry for each SYN that has arrived from a client for which the server is awaiting completion of the TCP three-way handshake. These sockets are in the SYN_RCVDstate (Figure 2.4).

A completed connection queue, which contains an entry for each client with whom the TCP three-way handshake has completed. These sockets are in the ESTABLISHEDstate (Figure 2.4). These two queues are depicted in the figure below:

When an entry is created on the incomplete queue, the parameters from the listen socket are copied over to the newly created connection. The connection creation mechanism is completely automatic; the server process is not involved.

要理解backlog参数,我们必须意识到对于给定的侦听套接字,内核维护两个队列:

一个不完整的连接队列,其中包含从客户端到达的每个 SYN 的条目,服务器正在等待其完成 TCP 三向握手。这些插座处于 SYN_RCVD状态(图 2.4)。

一个已完成的连接队列,其中包含与已完成 TCP 三向握手的每个客户端的条目。这些插座处于ESTABLISHED状态(图 2.4)。这两个队列如下图所示:

当在不完整队列上创建一个条目时,来自监听套接字的参数被复制到新创建的连接。连接创建机制是完全自动的;不涉及服务器进程。