What is lagging in TCP connections?

Below you see a python program that acts as a server listening for requests to connect to port 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 question is what is the function parameter of the socket.listen() method (i.e. socket.listen() 5 ).

Based on online tutorials:

The backlog argument specifies the maximum number of connections in the queue and must be at least 0; the maximum value depends on the system (usually 5), the minimum value is 0.

But:

  1. What are these queues?
  2. Does this matter for customer requests? (I mean, is the server working with socket.listen(5) different from the server working with socket.listen(1) when accepting connection requests or when receiving data?)
  3. Why is the minimum value equal to zero? Shouldn't there be at least 1 ?
  4. Is there a preferred value?
  5. Is this backlog specific to TCP connections or is it also applicable to UDP and other protocols?
+22
source share
3 answers

NOTE. Answers are drawn up without any experience in Python, but the questions are not related to the language to be answered.

What are these queues?

Simply put, the backlog parameter specifies the number of pending connections that the queue will hold.

When multiple clients connect to the server, the server holds incoming requests in the queue. Clients are queued, and the server processes their requests one by one, as and when the queue participant continues to work. The nature of this type of connection is called queuing.

Does this matter for customer requests? (I mean, is the server working with socket.listen(5) different from the server working with socket.listen(1) when accepting connection requests or when receiving data?)

Yes, both cases are different. In the first case, it would be possible to place only 5 clients in the queue; whereas in the case of backlog = 1, only 1 connection can be held in the queue, which leads to the removal of a further connection request!

Why is the minimum value equal to zero? Shouldn't there be at least 1?

I have no idea about Python, but according to this source , in C, the backlog 0 argument can allow the socket to accept connections, in which case the length of the listen queue can be set to the minimum value determined by the implementation.

Is there a preferred value?

There is no clear answer to this question. I would say that it depends on the nature of your application, as well as the hardware and software configuration. Again, according to the source, BackLog quietly limited from 1 to 5 inclusive (again, according to C).

Is this lag only for TCP connections or is it also applicable for UDP and other protocols?

NO Note that there is no need to listen () or accept () for unconnected datagram sockets (UDP). This is one of the benefits of using unconnected socket datagrams!

But keep in mind that there are implementations of TCP-based datagram sockets (called TCPDatagramSocket) that have a backlog parameter.

+30
source

When a TCP connection is established, a so-called three-way handshake is performed. Both parties exchange some packages, and as soon as they do, this connection is called completed, and it is ready for use by the application.

However, this three-way handshake takes some time. And during this time, the connection is queued, and this lag. Thus, you can set the maximum number of incomplete parallel connections using .listen(no) (note that according to the posix standard, the value is just a hint , it can be completely ignored). If someone tries to establish a connection above the limit of unfulfilled obligations, the other side will refuse it.

Thus, the limit of outstanding tasks refers to incomplete connections, but is not set.

Now a higher lag limit will be better in most cases. Please note that the maximum limit is OS dependent, e.g. cat/proc/sys/net/core/somaxconn gives me 128 on my Ubuntu.

+17
source

It seems that the function of this parameter is to limit the number of incoming connection requests that the server will store in the queue, assuming that it can serve the current request and a small number of waiting requests in the queue for a reasonable period of time under high load. Here is a good paragraph that I came across that gives a little context around this argument ...

Finally, the listening argument tells the socket library that we want it to queue up to 5 connection requests (normal maximum) before rejecting external connections. If the rest of the code is written correctly, this should be enough.

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

Previously, the document contained text that suggested clients connect and disconnect from the server so that you would not create a long queue of requests in the first place ...

When connect complete, socket s can be used to send a request to the page text. The same socket will read the response and then be destroyed. That's right, destroyed. Client sockets are usually used for only one exchange (or a small set of consecutive exchanges).

The HowTo related guide is a must-have when reading about socket programming for network programming. It really focuses on some of the big picture themes. Now, as the server socket manages this queue, how much implementation details is another story, perhaps interesting. I believe that the motivation for this design is more indicative; without this , a denial of service barrier would be very, very low.

As for the reason for the minimum value of 0 versus 1, we must remember that 0 is still a valid value, i.e. don't queue anything. In essence, this means that there will be no request queue, just reject the connection if the server socket is currently servicing the connection. In this context, you should always remember the service point of the active connection, the only reason why the queue will be interesting in the first place.

This brings us to the next issue of preferred cost. This is all a design decision, do you want to queue requests or not? If so, you can choose a value that, in your opinion, is justified based on expected traffic and known hardware resources, I suppose. I doubt that there is anything formal in choosing a value. This makes me think about how easy the request is in the first place, when you will be fined for posting anything on the server.


UPDATE

I wanted to justify the comments from user207421 and went looking for the source in python. Unfortunately, this level of detail is not in the sockets.py source , but in socketmodule. C # L3351-L3382 with a hash of 530f506.

The comments are very useful, I will copy the verbatim source below and highlight the explanatory comments that quite illuminate ...

We try to select a high enough level of default jobs to avoid connection failures for normal workloads, but not too high to limit resource usage.

and

If the lag is specified, it must be at least 0 (if it is less, it is 0); it indicates the number of unacceptable connections that the system will allow before refusing new connections. If not specified, a reasonable default is selected.

 /* 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 rabbit hole into the outer space, I discovered the following source from the socket module ...

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

This source ends in socket.h and is shortened using Linux as a specific background platform for discussion purposes.

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

There you can find more information in the help page.

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

 int listen(int sockfd, int backlog); 

And related documentation

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

The sockfd argument is a file descriptor that refers to a socket of type SOCK_STREAM or SOCK_SEQPACKET .

The backlog argument specifies the maximum length to which the queue of pending connections for sockfd can increase. If the connection request arrives when the queue is full, the client may receive an error indicating ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored, so the subsequent ECONNREFUSED connection will be ECONNREFUSED .

One additional source defines the kernel as responsible for the backlog of work.

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

Next, they will briefly talk about how invalid / queued connections are distributed in a pool (a useful picture is included in a linked source).

To understand the backlog argument, we must understand that for a given listening socket, the kernel supports two queues:

An incomplete connection queue that contains an entry for each SYN received from a client for which the server is waiting for the TCP three-way handshake to complete. These sockets are in the SYN_RCVD state (Figure 2.4).

A complete connection queue that contains an entry for each client that has completed a three-way TCP handshake. These sockets are in the ESTABLISHED state (Figure 2.4). These two lines are shown in the figure below:

When an entry is created in an incomplete queue, parameters from the listening socket are copied to the newly created connection. The mechanism for creating a connection is fully automatic; The server process is not involved.

-1
source

Source: https://habr.com/ru/post/1247026/


All Articles