python - 尝试连接多个 IP 地址并获取第一个成功的
问题描述
有没有办法socket
尝试连接到多个 IP 地址并获得第一个成功的 IP 地址?
一个简化的概念是这样的:
targets = ['1.2.3.4', '2.3.4.5', '3.4.5.6']
try:
s = socket_try_connect_one(targets, port=80, timeout=300)
# at this point, s contains the socket connection to one of the targets
except TimeoutError:
print('Cannot connect to any servers!')
sys.exit(1)
我应该如何实施socket_try_connect_one
才能获得预期的行为?是否有内置方法(在标准库中)可以做到这一点?
编辑添加:
我正在避免使用多线程/多处理,因为对于这个简单的需求来说这可能是多余的。
相反,我正在寻找类似于的东西.setblocking(0)
,但在连接建立期间应用(setblocking 适用于send()
and recv()
)。和类似的东西select.select
但适用于连接建立的东西(而不是触发 I/O)。
解决方案
因此,大致从标准库socket.create_connection
函数中借用,该函数为为任何给定主机名解析的每个 IP 连接到多个地址/端口对,并使用阻塞套接字按照 DNS 返回的 IP 地址序列完成连接。可以通过以下函数粗略地调整它以接受多个原始 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
可能是有益的,提供的示例函数仅用于说明非阻塞循环的外观以及它应该如何工作。
推荐阅读
- python - Tkinter .set() 和 *
- tracking - 多个 Azure kinect 的最低系统要求
- .net - ILMerge,不允许未解析的程序集引用:System.Runtime
- node.js - 需要帮助在 NodeJS 中使用 Sinon 存根异步 / 等待承诺
- javascript - 如何在更改之前获取 TextInput 的值?
- go - 测试时“无法在 Go Routine 中启动 NATS 服务器”
- android - 如何在没有 WorkContinuation 的情况下将顺序工作排入队列
- angular - Angular 依赖提供者没有提供指定的备用类
- python - 有没有办法让一个盒子在 vpython 中反射?
- c# - 存储库不会随着 UnitOfWorks 保存的更改而更新