from tornado.log import app_log
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream, SSLIOStream
-from tornado.netutil import bind_sockets, add_accept_handler, ssl_wrap_socket
+from tornado.netutil import (
+ bind_sockets,
+ add_accept_handler,
+ ssl_wrap_socket,
+ _DEFAULT_BACKLOG,
+)
from tornado import process
from tornado.util import errno_from_exception
'keyfile "%s" does not exist' % self.ssl_options["keyfile"]
)
- def listen(self, port: int, address: str = "") -> None:
+ def listen(
+ self,
+ port: int,
+ address: Optional[str] = None,
+ family: socket.AddressFamily = socket.AF_UNSPEC,
+ backlog: int = _DEFAULT_BACKLOG,
+ flags: Optional[int] = None,
+ reuse_port: bool = False,
+ ) -> None:
"""Starts accepting connections on the given port.
This method may be called more than once to listen on multiple ports.
`listen` takes effect immediately; it is not necessary to call
- `TCPServer.start` afterwards. It is, however, necessary to start
- the `.IOLoop`.
+ `TCPServer.start` afterwards. It is, however, necessary to start the
+ event loop if it is not already running.
+
+ All arguments have the same meaning as in
+ `tornado.netutil.bind_sockets`.
+
+ .. versionchanged:: 6.2
+
+ Added ``family``, ``backlog``, ``flags``, and ``reuse_port``
+ arguments to match `tornado.netutil.bind_sockets`.
"""
- sockets = bind_sockets(port, address=address)
+ sockets = bind_sockets(
+ port,
+ address=address,
+ family=family,
+ backlog=backlog,
+ flags=flags,
+ reuse_port=reuse_port,
+ )
self.add_sockets(sockets)
def add_sockets(self, sockets: Iterable[socket.socket]) -> None:
port: int,
address: Optional[str] = None,
family: socket.AddressFamily = socket.AF_UNSPEC,
- backlog: int = 128,
+ backlog: int = _DEFAULT_BACKLOG,
+ flags: Optional[int] = None,
reuse_port: bool = False,
) -> None:
"""Binds this server to the given port on the given address.
- To start the server, call `start`. If you want to run this server
- in a single process, you can call `listen` as a shortcut to the
- sequence of `bind` and `start` calls.
+ To start the server, call `start`. If you want to run this server in a
+ single process, you can call `listen` as a shortcut to the sequence of
+ `bind` and `start` calls.
Address may be either an IP address or hostname. If it's a hostname,
- the server will listen on all IP addresses associated with the
- name. Address may be an empty string or None to listen on all
- available interfaces. Family may be set to either `socket.AF_INET`
- or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise
- both will be used if available.
+ the server will listen on all IP addresses associated with the name.
+ Address may be an empty string or None to listen on all available
+ interfaces. Family may be set to either `socket.AF_INET` or
+ `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise both
+ will be used if available.
- The ``backlog`` argument has the same meaning as for
- `socket.listen <socket.socket.listen>`. The ``reuse_port`` argument
- has the same meaning as for `.bind_sockets`.
+ The ``backlog`` argument has the same meaning as for `socket.listen
+ <socket.socket.listen>`. The ``reuse_port`` argument has the same
+ meaning as for `.bind_sockets`.
- This method may be called multiple times prior to `start` to listen
- on multiple ports or interfaces.
+ This method may be called multiple times prior to `start` to listen on
+ multiple ports or interfaces.
.. versionchanged:: 4.4
Added the ``reuse_port`` argument.
+
+ .. versionchanged:: 6.2
+ Added the ``flags`` argument to match `.bind_sockets`.
"""
sockets = bind_sockets(
- port, address=address, family=family, backlog=backlog, reuse_port=reuse_port
+ port,
+ address=address,
+ family=family,
+ backlog=backlog,
+ flags=flags,
+ reuse_port=reuse_port,
)
if self._started:
self.add_sockets(sockets)
try:
result = subprocess.run(
sys.executable,
- capture_output=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
input=code,
encoding="utf8",
check=True,
)
except subprocess.CalledProcessError as e:
raise RuntimeError(
- f"Process returned {e.returncode} stdout={e.stdout}"
+ f"Process returned {e.returncode} output={e.stdout}"
) from e
return result.stdout
)
out = self.run_subproc(code)
self.assertEqual("".join(sorted(out)), "012")
+
+ def test_reuse_port(self):
+ code = textwrap.dedent(
+ """
+ import socket
+ from tornado.ioloop import IOLoop
+ from tornado.netutil import bind_sockets
+ from tornado.process import task_id, fork_processes
+ from tornado.tcpserver import TCPServer
+
+ # Pick an unused port which we will be able to bind to multiple times.
+ (sock,) = bind_sockets(0, address='127.0.0.1',
+ family=socket.AF_INET, reuse_port=True)
+ port = sock.getsockname()[1]
+
+ fork_processes(3)
+ server = TCPServer()
+ server.listen(port, address='127.0.0.1', reuse_port=True)
+ IOLoop.current().run_sync(lambda: None)
+ print(task_id(), end='')
+ """
+ )
+ out = self.run_subproc(code)
+ self.assertEqual("".join(sorted(out)), "012")
import numbers
import os.path
import re
+import socket
import sys
import threading
import time
import tornado.locale
from tornado import locale
from tornado.log import access_log, app_log, gen_log
+import tornado.netutil
from tornado import template
from tornado.escape import utf8, _unicode
from tornado.routing import (
autoreload.start()
- def listen(self, port: int, address: str = "", **kwargs: Any) -> HTTPServer:
+ def listen(
+ self,
+ port: int,
+ address: Optional[str] = None,
+ *,
+ family: socket.AddressFamily = socket.AF_UNSPEC,
+ backlog: int = tornado.netutil._DEFAULT_BACKLOG,
+ flags: Optional[int] = None,
+ reuse_port: bool = False,
+ **kwargs: Any
+ ) -> HTTPServer:
"""Starts an HTTP server for this application on the given port.
This is a convenience alias for creating an `.HTTPServer`
.. versionchanged:: 4.3
Now returns the `.HTTPServer` object.
+
+ .. versionchanged:: 6.2
+ Added support for new keyword arguments in `.TCPServer.listen`,
+ including ``reuse_port``.
"""
server = HTTPServer(self, **kwargs)
- server.listen(port, address)
+ server.listen(
+ port,
+ address=address,
+ family=family,
+ backlog=backlog,
+ flags=flags,
+ reuse_port=reuse_port,
+ )
return server
def add_handlers(self, host_pattern: str, host_handlers: _RuleList) -> None: