diff --git a/tornado/netutil.py b/tornado/netutil.py index 15eea9704f..d7d509ea76 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -48,15 +48,23 @@ # For undiagnosed reasons, 'latin1' codec may also need to be preloaded. u"foo".encode("latin1") -# Default backlog used when calling sock.listen() -_DEFAULT_BACKLOG = 128 +# Default backlog used when calling sock.listen(); if `None`, no value is +# passed to `socket.listen` implying normally that Python will decide on +# the backlog size for the socket. For Python < 3.6, an error will be +# raised by `socket.listen` if no argument is provided. +DEFAULT_BACKLOG = None + +# Number of connections to try and accept in one sweep of an I/O loop; +# if falsy (e.g. `None` or zero) the number will be decided on +# automatically. +ACCEPT_CALLS_PER_EVENT_LOOP = None def bind_sockets( port: int, address: Optional[str] = None, family: socket.AddressFamily = socket.AF_UNSPEC, - backlog: int = _DEFAULT_BACKLOG, + backlog: Optional[int] = None, flags: Optional[int] = None, reuse_port: bool = False, ) -> List[socket.socket]: @@ -74,7 +82,8 @@ def bind_sockets( both will be used if available. The ``backlog`` argument has the same meaning as for - `socket.listen() `. + `socket.listen() ` if it carries an integer + value; if `None`, the backlog size is chosen automatically. ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``. @@ -181,7 +190,7 @@ def bind_sockets( else: raise bound_port = sock.getsockname()[1] - sock.listen(backlog) + listen(sock, backlog) sockets.append(sock) return sockets @@ -189,7 +198,7 @@ def bind_sockets( if hasattr(socket, "AF_UNIX"): def bind_unix_socket( - file: str, mode: int = 0o600, backlog: int = _DEFAULT_BACKLOG + file: str, mode: int = 0o600, backlog: Optional[int] = None ) -> socket.socket: """Creates a listening unix socket. @@ -219,7 +228,7 @@ def bind_unix_socket( raise ValueError("File %s exists and is not a socket", file) sock.bind(file) os.chmod(file, mode) - sock.listen(backlog) + listen(sock, backlog) return sock @@ -258,7 +267,7 @@ def accept_handler(fd: socket.socket, events: int) -> None: # Instead, we use the (default) listen backlog as a rough # heuristic for the number of connections we can reasonably # accept at once. - for i in range(_DEFAULT_BACKLOG): + for i in range(ACCEPT_CALLS_PER_EVENT_LOOP or DEFAULT_BACKLOG or 128): if removed[0]: # The socket was probably closed return @@ -621,3 +630,12 @@ def ssl_wrap_socket( return context.wrap_socket(socket, server_hostname=server_hostname, **kwargs) else: return context.wrap_socket(socket, **kwargs) + + +def listen(socket: socket.socket, backlog: int = None): + """A helper procedure to better delegate `socket.listen` calls where + backlog may or may not be specified. + """ + if backlog is None: + backlog = DEFAULT_BACKLOG + return socket.listen(backlog) if backlog is not None else socket.listen()