在同一台 Windows 主機上使用相同多播群組的多個應用程式

在同一台 Windows 主機上使用相同多播群組的多個應用程式

我是一名軟體工程師,設計了一個分散式軟體,其中啟動過程利用 IP 多播來發現其對等點。軟體本身會作為不同的可執行模組進行分發,因此,有時在同一台主機上運行多個可執行模組是有意義的。這就是我的問題開始的地方,因為在我看來,Windows 不擅長管理訂閱單一多播群組的多個進程。

我的目標是能夠自由地選擇在哪些主機上啟動哪些可執行文件,並且這些可執行文件將在沒有任何預定義知識的情況下發現其所有對等方(無論是在同一主機上還是在其他主機上)。

到目前為止,故障排除顯示問題出在 Windows 如何處理多個進程訂閱相同多播群組的情況,因為:

  1. 如果同一進程用於在同一台機器上發送和接收多播資料報,則它會按預期工作。該進程可以分成多個線程,沒有任何問題。

  2. 如果我運行不同的發送和接收進程,儘管群組加入訊息和所有資料封包都顯示在 Wireshark 中,但接收進程不會收到任何訊息。

  3. 如果我在監聽之前也使用相同的套接字將封包傳送到我已加入的多重播放群組,則 2 中所述的場景有效。然後,後者在未指定的時間內接收多播資料報,然後僅停止接收資料報(它一直等待資料報到來)。數據報已確認使用 Wireshark 發送至網路或從網路發送。

  4. 我的最新發現表明,如果我定期向我訂閱的群組發送多播訊息,我會收到發送到該多播群組的資料報,這些資料報也來自同一主機上的其他進程。

據我所知,IP 多播僅定義之間的通信主機,而作業系統有責任將傳入資料包重新導向到適當的位置應用。由於資料包似乎總是出現在 Wireshark 中,即使應用程式沒有接收它們,Windows 似乎也無法處理傳入的資料包,或至少無法將它們傳遞給適當的應用程式。

如果有人能夠證實或拒絕我的推理,並為我指出如何解決這個問題的正確方向,我將不勝感激。目標是能夠使同一主機上的多個應用程式加入單一多播群組通道並接收訊息,而無需向多播群組發送「垃圾」以便它們接收資料(解決方法描述為點號) 4).

我正在使用 Java 進行實現,如果需要,可以在此處發布 MWE。然而,我擔心它可能會將焦點從場景轉移到編程,這不是這裡關注的問題(從我可以推斷的問題來看)。

答案1

OP 正在尋求一種方法來發現網路上的對等點,而無需了解這些對等點。這個來源mDNS 至少需要了解每個對等點的主機名稱。

因此,mDNS 並不是上述問題的可行解決方案。

根據對於這個答案,關於多播,您所要求的是可能的。它涉及使用 SO_REUSEADDR 套接字選項。當您使用此套接字選項時,它允許多個套接字偵聽相同位址:連接埠組合,只要;

  1. 該位址是組播位址;和
  2. 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 設定為空白字串,這表示您實際上會偵聽所有多播位址群組。這似乎是視窗或我的知識的限制,可能是後者。

無論哪種方式,在 MCAST_GRP 變數中使用特定位址都會導致錯誤,因此使用空白字串至少可以獲得解決 OP 描述的問題的程式碼。

該程式碼可以在同一進程中多次重複使用,儘管我尚未測試多個進程是否可以成功使用它。我已經使用 python 的 asyncio 框架進行了測試,因此多個套接字在同一線程中偵聽。

順便說一句,為了跨平台支持,您還可以讓此程式碼在 nix 作業系統上運行,並且在這些系統上您可以將 MCAST_GRP 設定為特定位址。

編輯:

我最近遇到此資源來自 MS它給出了一個似乎允許使用特定多播群組位址而不是綁定到所有群組位址的範例。它涉及在multicast_grp_req變數中設定更多選項。此外,該範例是 C++ 程式碼,而不是 python,但它們足夠相似,足以了解要點。

希望這可以幫助 :)

相關內容