[英]Linux UDP Socket/Port Reuse
我正在嘗試Linux UDP套接字。 我有一個服務器和客戶端,它們通過以下方式相互通信。
服務器:將端口X上的廣播公告發送到其子網中的所有IP。
客戶端:通過向服務器發送單播消息來響應公告。 該消息直接發送回端口X。
在服務器上,我有一個線程定期發送通知。 現在,我想添加更多代碼以接收來自客戶端的響應以及向特定客戶端發送單播消息。 我對服務器的提議方案如下所示。
沒有特別的順序,這是我的問題(對我來說,我是unix套接字編程的新手):
我需要在兩個插槽之間進行任何鎖定還是在操作系統中處理? 也就是說,由於兩個端口都使用相同的端口,我可以同時向兩個套接字發送數據並且不會發生一些奇怪的沖突嗎?
我是否需要擔心線程2接收到兩個“發送者”線程發送的數據? 我該如何預防?
我需要啟用任何選項才能進行這項工作嗎? 在單播廣播(socket_b)之前設置廣播套接字(socket_a)是否重要?
我應該在端口X上創建專用的“接收”套接字嗎? 也就是說,擁有一個僅用於接收數據的套接字是否有意義? 這是唯一可以調用bind()的套接字。
鑒於所有三個線程都使用相同的端口,我是否還要擔心其他問題? 不幸的是,這是我正在使用的約束。 如果上述方案是不可能的,我可能不得不重新審視我的一個端口設計。
預先感謝您的幫助。
我認為這行不通。 當您將UDP套接字多次綁定到同一個ip + port時,發往該ip + port的數據包將被傳遞到任何套接字。 因此,從對等方到您的ip +端口的單播回復可能會傳遞到三個套接字中的任何一個。 當鎖定此類數據包時,此行為非常合乎邏輯:從OS的角度來看,udp數據包包含源ip + port和目標ip + port。 而且由於所有套接字僅綁定到目標ip + port,僅此而已,因此任何套接字都可能在最后得到答復。
因此,您可能需要圍繞單個套接字重構應用程序,該套接字將用於單播和廣播,並且將接收所有答復並進行處理。 如果您堅持使用多個線程,則可以使用同一套接字從所有線程發送消息而無需鎖定,但是您只能在一個線程中接收。 在此線程中,您需要確定數據包的類型,然后可以將其“提供”給正確的線程。
我需要在兩個插槽之間進行任何鎖定還是在操作系統中處理? 也就是說,由於兩個端口都使用相同的端口,我可以同時向兩個套接字發送數據並且不會發生一些奇怪的沖突嗎?
對於UDP,不需要鎖定。 就是說,您可能仍然發現為每個線程簡單地創建一個單獨的套接字還是比較容易的,即使僅僅是因為安全地協調關閉和銷毀多個線程正在使用的套接字可能會有些棘手。
我是否需要擔心線程2接收到兩個“發送者”線程發送的數據? 我該如何預防?
是的,線程2可能至少會看到廣播數據包,也可能會看到單播數據包(如果它們曾經發送到運行線程2的計算機,則可能)。 避免這種情況的最簡單方法是改為偵聽其他端口(例如,將廣播數據包發送到端口X,但讓客戶端將其單播回復數據包發送回端口X + 1;這樣,您在端口X上收到的任何數據包+1幾乎可以肯定是來自客戶端的單播回復)
我需要啟用任何選項才能進行這項工作嗎?
只是SO_BROADCAST之一,AFAIK。 (如果您希望同一台計算機上的多個套接字偵聽同一端口,則還需要執行SO_REUSEADDR和[在MacOS / X下] SO_REUSEPORT,但希望您不需要這樣做)
在單播廣播(socket_b)之前設置廣播套接字(socket_a)是否重要?
不,訂購應該無關緊要。
我應該在端口X上創建專用的“接收”套接字嗎? 也就是說,擁有一個僅用於接收數據的套接字是否有意義? 這是唯一可以調用bind()的套接字。
您可以這樣做,但是具有相同的套接字發送和接收也可以工作。 (請注意,如果您使用阻塞I / O,則必須注意recv()長時間未返回,這可能會阻止您的線程同時執行其他任何操作,例如同時發送-這就是為什么我幾乎總是在我的程序中使用非阻塞I / O和select()這樣,就可以使用一個線程來完成我想做的所有事情,這使我避免了所有不確定性和潛在的競爭條件以及多個死鎖線程)
鑒於所有三個線程都使用相同的端口,我是否還要擔心其他問題? 不幸的是,這是我正在使用的約束。 如果上述方案是不可能的,我可能不得不重新審視我的一個端口設計。
使用單個端口將起作用,只要准備好在其上接收自己的廣播數據包即可(即在發生這種情況時不要進入反饋循環)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.