2 台のコンピューターのいずれかで実行できるアプリ X がありますが、一度に 1 台しか実行できません。Python で記述された別のアプリ Y があります。この 2 つの IP アドレスから、アプリ X (存在する場合) を実行しているコンピューターを特定する必要があります。ポートでリッスンし、データを受信するたびに「Hello」で応答する UDP サービスを使用することで、これを部分的に解決しました。クライアントは、各アドレスのアプリ 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 アドレスをキャッシュする必要がありますか? これらまたは他のアイデアをどのようにコーディングしますか?
ありがとう。
編集:これは、選択を使用した私の改訂されたコードです:
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