Таким образом, примерно заимствуя из стандартной библиотеки socket.create_connection
функцию, которая выполняет подключение к нескольким парам адрес / порт для каждого IP-адреса, разрешенного для любого заданного имени хоста, при этом подключение выполняется с использованием блокирующих сокетов, следуя последовательностиIP-адреса, возвращаемые DNS.Адаптировать его для приема нескольких необработанных IP-адресов и использования неблокирующих сокетов можно примерно с помощью следующей функции:
import socket
import errno
def make_socket_from_addresses(addresses, port, *args, **kwargs):
sockets = {} # mapping of the actively checked sockets
dests = [] # the list of all destination pairs
for address in addresses:
dest = (address, port)
sock = socket.socket(*args, **kwargs)
sock.setblocking(0)
sockets[dest] = sock
dests.append(dest)
result = None
while sockets and result is None:
for dest in dests:
sock = sockets.get(dest)
if not sock:
continue
code = sock.connect_ex(dest)
if code == 0:
# success, track the result.
result = sock
sockets.pop(dest)
break
elif code not in (errno.EALREADY, errno.EINPROGRESS):
# assume any not already/in-progress are invalid/dead and so
# prune them.
sockets.pop(dest)
# should insert some very minute timeout here
for _, sock in sockets.items():
# close any remaining sockets
sock.close()
return result
Чтобы использовать эту функцию, список адресов для проверки и портдолжен быть указан вместе с соответствующими аргументами для конструктора socket.socket
.Например:
# various google.com addresses
addresses = ['216.58.203.110', '172.217.25.46', '172.217.6.78']
port = 80
sock = make_socket_from_addresses(
addresses, port, socket.AF_INET, socket.SOCK_STREAM)
print(sock)
Выполнение этого:
<socket.socket fd=3, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('10.0.0.1', 59454), raddr=('172.217.25.46', 80)>
Использование select
может быть полезным, приведенная в качестве примера функция служит только в качестве иллюстрации того, как неблокирующий цикл можеткак выглядит и как должно работать.