mirror of https://github.com/python/cpython
Merge 3.4 (asyncio)
This commit is contained in:
commit
7b58a2bb1d
|
@ -333,9 +333,12 @@ Creating listening connections
|
|||
|
||||
Parameters:
|
||||
|
||||
* If *host* is an empty string or ``None``, all interfaces are assumed
|
||||
and a list of multiple sockets will be returned (most likely
|
||||
one for IPv4 and another one for IPv6).
|
||||
* The *host* parameter can be a string, in that case the TCP server is
|
||||
bound to *host* and *port*. The *host* parameter can also be a sequence
|
||||
of strings and in that case the TCP server is bound to all hosts of the
|
||||
sequence. If *host* is an empty string or ``None``, all interfaces are
|
||||
assumed and a list of multiple sockets will be returned (most likely one
|
||||
for IPv4 and another one for IPv6).
|
||||
|
||||
* *family* can be set to either :data:`socket.AF_INET` or
|
||||
:data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. If not set
|
||||
|
@ -369,6 +372,10 @@ Creating listening connections
|
|||
The function :func:`start_server` creates a (:class:`StreamReader`,
|
||||
:class:`StreamWriter`) pair and calls back a function with this pair.
|
||||
|
||||
.. versionchanged:: 3.5.1
|
||||
|
||||
The *host* parameter can now be a sequence of strings.
|
||||
|
||||
|
||||
.. coroutinemethod:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import collections
|
|||
import concurrent.futures
|
||||
import heapq
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
|
@ -786,6 +787,15 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
|
||||
return transport, protocol
|
||||
|
||||
@coroutine
|
||||
def _create_server_getaddrinfo(self, host, port, family, flags):
|
||||
infos = yield from self.getaddrinfo(host, port, family=family,
|
||||
type=socket.SOCK_STREAM,
|
||||
flags=flags)
|
||||
if not infos:
|
||||
raise OSError('getaddrinfo({!r}) returned empty list'.format(host))
|
||||
return infos
|
||||
|
||||
@coroutine
|
||||
def create_server(self, protocol_factory, host=None, port=None,
|
||||
*,
|
||||
|
@ -795,7 +805,13 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
backlog=100,
|
||||
ssl=None,
|
||||
reuse_address=None):
|
||||
"""Create a TCP server bound to host and port.
|
||||
"""Create a TCP server.
|
||||
|
||||
The host parameter can be a string, in that case the TCP server is bound
|
||||
to host and port.
|
||||
|
||||
The host parameter can also be a sequence of strings and in that case
|
||||
the TCP server is bound to all hosts of the sequence.
|
||||
|
||||
Return a Server object which can be used to stop the service.
|
||||
|
||||
|
@ -813,13 +829,18 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
|
||||
sockets = []
|
||||
if host == '':
|
||||
host = None
|
||||
hosts = [None]
|
||||
elif (isinstance(host, str) or
|
||||
not isinstance(host, collections.Iterable)):
|
||||
hosts = [host]
|
||||
else:
|
||||
hosts = host
|
||||
|
||||
infos = yield from self.getaddrinfo(
|
||||
host, port, family=family,
|
||||
type=socket.SOCK_STREAM, proto=0, flags=flags)
|
||||
if not infos:
|
||||
raise OSError('getaddrinfo() returned empty list')
|
||||
fs = [self._create_server_getaddrinfo(host, port, family=family,
|
||||
flags=flags)
|
||||
for host in hosts]
|
||||
infos = yield from tasks.gather(*fs, loop=self)
|
||||
infos = itertools.chain.from_iterable(infos)
|
||||
|
||||
completed = False
|
||||
try:
|
||||
|
|
|
@ -305,7 +305,8 @@ class AbstractEventLoop:
|
|||
|
||||
If host is an empty string or None all interfaces are assumed
|
||||
and a list of multiple sockets will be returned (most likely
|
||||
one for IPv4 and another one for IPv6).
|
||||
one for IPv4 and another one for IPv6). The host parameter can also be a
|
||||
sequence (e.g. list) of hosts to bind to.
|
||||
|
||||
family can be set to either AF_INET or AF_INET6 to force the
|
||||
socket to use IPv4 or IPv6. If not set it will be determined
|
||||
|
|
|
@ -745,6 +745,39 @@ class EventLoopTestsMixin:
|
|||
self.assertEqual(cm.exception.errno, errno.EADDRINUSE)
|
||||
self.assertIn(str(httpd.address), cm.exception.strerror)
|
||||
|
||||
@mock.patch('asyncio.base_events.socket')
|
||||
def create_server_multiple_hosts(self, family, hosts, mock_sock):
|
||||
@asyncio.coroutine
|
||||
def getaddrinfo(host, port, *args, **kw):
|
||||
if family == socket.AF_INET:
|
||||
return [[family, socket.SOCK_STREAM, 6, '', (host, port)]]
|
||||
else:
|
||||
return [[family, socket.SOCK_STREAM, 6, '', (host, port, 0, 0)]]
|
||||
|
||||
def getaddrinfo_task(*args, **kwds):
|
||||
return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
|
||||
|
||||
if family == socket.AF_INET:
|
||||
mock_sock.socket().getsockbyname.side_effect = [(host, 80)
|
||||
for host in hosts]
|
||||
else:
|
||||
mock_sock.socket().getsockbyname.side_effect = [(host, 80, 0, 0)
|
||||
for host in hosts]
|
||||
self.loop.getaddrinfo = getaddrinfo_task
|
||||
self.loop._start_serving = mock.Mock()
|
||||
f = self.loop.create_server(lambda: MyProto(self.loop), hosts, 80)
|
||||
server = self.loop.run_until_complete(f)
|
||||
self.addCleanup(server.close)
|
||||
server_hosts = [sock.getsockbyname()[0] for sock in server.sockets]
|
||||
self.assertEqual(server_hosts, hosts)
|
||||
|
||||
def test_create_server_multiple_hosts_ipv4(self):
|
||||
self.create_server_multiple_hosts(socket.AF_INET,
|
||||
['1.2.3.4', '5.6.7.8'])
|
||||
|
||||
def test_create_server_multiple_hosts_ipv6(self):
|
||||
self.create_server_multiple_hosts(socket.AF_INET6, ['::1', '::2'])
|
||||
|
||||
def test_create_server(self):
|
||||
proto = MyProto(self.loop)
|
||||
f = self.loop.create_server(lambda: proto, '0.0.0.0', 0)
|
||||
|
|
Loading…
Reference in New Issue