私は分散ソフトウェアを設計しているソフトウェア エンジニアです。このソフトウェアでは、起動手順で IP マルチキャストを使用してピアを検出します。ソフトウェア自体は異なる実行可能モジュールとして配布されるため、同じホストで複数の実行可能モジュールを実行することが理にかなっている場合があります。これが私の問題の始まりです。Windows は、単一のマルチキャスト グループにサブスクライブする複数のプロセスを管理するのが得意ではないように思われます。
私の目標は、どのホストでどの実行可能ファイルを起動するかを自由に選択できるようにし、これにより、事前定義された知識なしに、すべてのピア(同じホスト上または他のホスト上)が検出されるようにすることです。
これまでのところ、トラブルシューティングでは、問題は、複数のプロセスが同じマルチキャスト グループにサブスクライブするシナリオを Windows がどのように処理するかにあることが示されています。その理由は次のとおりです。
同じマシン上でマルチキャスト データグラムの送受信に同じプロセスを使用すると、期待どおりに動作します。プロセスは問題なく複数のスレッドに分割できます。
送信と受信に異なるプロセスを実行すると、グループ参加メッセージとすべてのデータグラムが Wireshark に表示されるにもかかわらず、受信プロセスは何も受信しません。
2 で説明したシナリオは、リッスンする前に同じソケットを使用して、参加しているマルチキャスト グループにパケットを送信する場合にも機能します。その後、後者は不特定の時間マルチキャスト データグラムを受信し、その後データグラムの受信を完全に停止します (データグラムが来るのを待ち続けます)。データグラムがネットワークとの間で送受信されていることは、Wireshark を使用して確認されます。
最新の調査結果によると、自分が加入しているグループにマルチキャスト メッセージを定期的に送信すると、同じホスト上の他のプロセスからもこのマルチキャスト グループに送信されたデータグラムを受信することがわかりました。
私の理解する限り、IPマルチキャストは、ホスト受信パケットを適切な宛先にリダイレクトするのはOSの責任である。応用アプリケーションがパケットを受信していなくても、パケットは常に Wireshark に表示されるように見えるため、Windows は受信パッケージの処理に失敗しているか、少なくとも適切なアプリケーションに配信できていないようです。
私の推論を肯定または否定し、この問題を解決する正しい方向を示してくださる方がいらっしゃいましたら、幸いです。目標は、同じホスト上の複数のアプリケーションが単一のマルチキャスト グループ チャネルに参加し、データを受信するためにマルチキャスト グループに「ジャンク」を送信する必要なくメッセージを受信できるようにすることです (回避策はポイント番号 4 で説明されています)。
私は実装に Java を使用しており、要求があればここに MWE を投稿できます。ただし、焦点がシナリオからプログラミングに移ってしまうのではないかと心配しています。これはここでは問題ではありません (私が推測できる限りでは)。
答え1
OPは、ネットワーク上のピアを、それらのピアについての知識なしに発見する方法を求めています。この情報源mDNS では、少なくとも各ピアのホスト名の知識が必要です。
結果として、mDNS は、説明したようにこの問題に対する実行可能な解決策ではありません。
によるとこの答えに対してマルチキャストについては、ご要望のことは可能です。SO_REUSEADDR ソケット オプションを使用します。このソケット オプションを使用すると、複数のソケットが同じアドレス:ポートの組み合わせでリッスンできるようになります。ただし、次の条件を満たす必要があります。
- アドレスはマルチキャストアドレスであり、
- SO_RESUSEADDR は、アドレス:ポートの組み合わせにバインドしようとするすべてのソケットに設定されます。
しかし、この答えまた、各ソケットに SO_BROADCAST を設定する必要もあるかもしれませんが、これは確かに直感的ではありません。ただし、Windows で Python を使用した私自身のテストでは、これを行う必要はありませんでした。したがって、この回答がどの程度正当なものであるかはわかりません。行き詰まった場合に備えて言及しますが、これはおそらく時代遅れであると考えており、現在は Windows 10 でテストしています。
これは私がテストしたコードの例で、エラーは発生しません。これは、ビーコンを使用してワーカー プロセスをブローカー プロセスに接続する自動テストの一部です。このテストは、単一ノードで実行すると合格しますが、複数のノードではまだテストしていません。
import socket, struct
MCAST_GRP = ''
MCAST_PORT = 1234
MULTICAST_TTL = 2
def create_beacon_listener():
sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM,
socket.IPPROTO_UDP
)
sock.setsockopt(
socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1
)
sock.setblocking(0)
sock.bind(( MCAST_GRP, MCAST_PORT ))
multicast_grp_req = struct.pack(
"4sl",
socket.inet_aton(MCAST_GRP),
socket.INADDR_ANY
)
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
multicast_grp_req
)
return sock
上記のコードは、目的のグループ アドレス MCAST_GRP とポート MCAST_PORT のリスニング ソケットを返します。また、MCAST_GRP は空の文字列に設定されています。つまり、実際にはすべてのマルチキャスト アドレス グループをリッスンしていることになります。これは、Windows または私の知識のいずれかの制限のようですが、おそらく後者です。
いずれにしても、MCAST_GRP 変数で特定のアドレスを使用するとエラーが発生するため、空の文字列を使用すると、少なくとも OP が説明した問題を解決するコードが取得されます。
このコードは、同じプロセス内で複数回再利用できます。ただし、複数のプロセスで正常に使用できるかどうかはまだテストしていません。Python の asyncio フレームワークを使用してテストしたので、複数のソケットが同じスレッドでリッスンしています。
余談ですが、クロスプラットフォームのサポートのために、このコードを nix オペレーティング システムでも動作させることができ、それらのシステムでは MCAST_GRP を特定のアドレスに設定できます。
編集:
最近出会ったMSからのこのリソースこれは、すべてにバインドするのではなく、特定のマルチキャスト グループ アドレスを使用できるようにする例を示しています。multicast_grp_req 変数にさらにいくつかのオプションを設定する必要があります。また、この例は Python ではなく C++ コードですが、要点は理解できる程度には似ています。
お役に立てれば :)