def bind_sockets(port, address=None, family=socket.AF_UNSPEC,
- backlog=_DEFAULT_BACKLOG, flags=None):
+ backlog=_DEFAULT_BACKLOG, flags=None, reuse_port=False):
"""Creates listening sockets bound to the given port and address.
Returns a list of socket objects (multiple sockets are returned if
``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like
``socket.AI_PASSIVE | socket.AI_NUMERICHOST``.
+
+ ``resuse_port`` option sets ``SO_REUSEPORT`` option for every socket
+ in the list. If your platform doesn't support this option ValueError will
+ be raised.
"""
+ if reuse_port and not hasattr(socket, "SO_REUSEPORT"):
+ raise ValueError("the platform doesn't support SO_REUSEPORT")
+
sockets = []
if address == "":
address = None
set_close_exec(sock.fileno())
if os.name != 'nt':
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ if reuse_port:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
if af == socket.AF_INET6:
# On linux, ipv6 sockets accept ipv4 too by default,
# but this makes it impossible to bind to both
from tornado.netutil import BlockingResolver, ThreadedResolver, is_valid_ip, bind_sockets
from tornado.stack_context import ExceptionStackContext
-from tornado.testing import AsyncTestCase, gen_test
+from tornado.testing import AsyncTestCase, gen_test, bind_unused_port
from tornado.test.util import unittest, skipIfNoNetwork
try:
finally:
for sock in sockets:
sock.close()
+
+ @unittest.skipIf(not hasattr(socket, "SO_REUSEPORT"), "SO_REUSEPORT is not supported")
+ def test_reuse_port(self):
+ socket, port = bind_unused_port(reuse_port=True)
+ try:
+ sockets = bind_sockets(port, 'localhost', reuse_port=True)
+ self.assertTrue(all(s.getsockname()[1] == port for s in sockets))
+ finally:
+ socket.close()
+ for sock in sockets:
+ sock.close()
return port
-def bind_unused_port():
+def bind_unused_port(reuse_port=False):
"""Binds a server socket to an available port on localhost.
Returns a tuple (socket, port).
"""
- [sock] = netutil.bind_sockets(None, 'localhost', family=socket.AF_INET)
+ [sock] = netutil.bind_sockets(None, 'localhost', family=socket.AF_INET,
+ reuse_port=reuse_port)
port = sock.getsockname()[1]
return sock, port