我有一个应用程序 X,它可以在两台计算机中的任何一台上运行,但一次只能在一台计算机上运行。我有另一个用 Python 编写的应用程序 Y,考虑到两个可能的 IP 地址,需要找出哪台计算机正在运行应用程序 X(如果有)。我通过有一个 UDP 服务来部分解决这个问题,该服务在端口上侦听并在收到一些数据时以“Hello”响应。客户端可以尝试将数据发送到每个地址上的应用程序 X 端口,如果收到响应,我知道应用程序正在该计算机上运行。
到目前为止,我的代码如下所示:
def ipaddress(self):
"""Test which side responds on the status port."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.settimeout(5)
s.sendto("status", (ADDR_A, PORT))
s.recvfrom(1024)
except socket.timeout:
try:
s.sendto("status", (ADDR_B, PORT))
s.recvfrom(1024)
except:
pass
else:
return ADDR_B
else:
return ADDR_A
finally:
s.close()
return None
这个函数的问题是,每当我想与运行应用程序 X 的计算机交谈时,它都会定期调用。它总是首先测试 ADDR_A,如果它没有运行应用程序 X,那么我必须等待套接字超时,然后再尝试 ADDR_B。尽管这种情况并不经常发生,但每当我再次尝试时,应用程序 X 可能会切换计算机。
有没有更好的办法?我想知道是否可以并行连接到两台计算机并在一台响应时立即返回?或者我应该缓存上次调用函数时首先响应的 IP 地址?我将如何编码这些或其他想法?
谢谢。
编辑:这是我使用 select 修改后的代码:
def ipaddress(addr_a, addr_b, timeout=5):
"""Test which side responds on the status port."""
# Create UDP sockets for each address
socks = [ socket.socket(socket.AF_INET, socket.SOCK_DGRAM),
socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
]
# Send some data to each socket
for sock, addr in zip(socks, (addr_a, addr_b)):
sock.connect(addr) # do explicit connect so getpeername works
sock.send("status")
# Wait for the first to respond if any
while socks:
waiting = select.select(socks, [], socks, timeout)[0]
if waiting:
for sock in waiting:
try:
data = sock.recv(1024)
if data:
return sock.getpeername()[0]
except Exception, e:
# Occasionally get [Errno 10054] which means socket isn't really
# available, so see if other responds instead...
socks.remove(sock)
else:
break # timeout occurred
return None