Python 尝试连接到多个IP地址并获取第一个成功的IP地址
有没有一种方法可以使用套接字尝试连接到多个IP地址并获得第一个成功的IP地址 一个简单的概念是: 目标=['1.2.3.4','2.3.4.5','3.4.5.6'] 尝试: s=套接字\u尝试\u连接\u onetargets,端口=80,超时=300 此时,s包含到其中一个目标的套接字连接 除时间错误外: 打印“无法连接到任何服务器!” sys.exit1 我应该如何实现socket\u try\u connect\u one以获得预期的行为?标准libs中是否有内置的方法来执行此操作 编辑以添加: 我避免使用多线程/多处理,因为对于这个简单的需求来说,这可能是一种过分的做法Python 尝试连接到多个IP地址并获取第一个成功的IP地址,python,sockets,Python,Sockets,有没有一种方法可以使用套接字尝试连接到多个IP地址并获得第一个成功的IP地址 一个简单的概念是: 目标=['1.2.3.4','2.3.4.5','3.4.5.6'] 尝试: s=套接字\u尝试\u连接\u onetargets,端口=80,超时=300 此时,s包含到其中一个目标的套接字连接 除时间错误外: 打印“无法连接到任何服务器!” sys.exit1 我应该如何实现socket\u try\u connect\u one以获得预期的行为?标准libs中是否有内置的方法来执行此操作 编辑
相反,我正在寻找类似于.setblocking0的东西,但在连接建立期间应用了setblocking,它适用于发送和接收。与select.select类似,但适用于建立连接,而不是在I/O时触发。因此大致借用标准库函数,该函数为任何给定主机名解析的每个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可能是有益的,提供的示例函数仅用于说明非阻塞循环的外观和工作原理。存在一些方法,这些方法使得线程的使用变得无关紧要。如果是这种情况,请更新该问题,以便它可以重新打开或使用实现此功能的实际替代问题线程关闭。@metatoaster我编辑了我的问题,以便更好地描述需求以及非阻塞套接字的链接答案可能不适用的原因。一种方法是使用Python 3的异步编程工具,我已经看到了一个很好的演示与三重奏,与增量退避真棒的答案,谢谢!我不知道socket.setblocking实际上也适用于连接。。。哇,我每天都在学习新东西!此外,在我的例子中,我必须添加一些更多的errno.*值作为“可接受”值,因为我的程序基本上需要等待一些端点准备就绪,因此简单的无法连接到该IP:端口是预期的。。。这就是为什么我在问题中添加了timeout参数。但你的回答让我走上了正确的道路。再次感谢大家!