2017-02-24 475 views
-1

我正在使用C#/ Winforms通過UDP與另一個系統進行通信。我正在使用DotNet的'UdpClient'類。我使用每個發射一個插座,以及一個用於接收:C#Winforms UDPClient異常:「每個套接字地址通常只允許使用一次。」

UdpClient client = new UdpClient(receiveport_num); 
client.Client.SetSocketOption(SocketOptionLevel.Socket,  SocketOptionName.ReuseAddress, true); 
client.Client.SetSocketOption(SocketOptionLevel.Socket,  SocketOptionName.ExclusiveAddressUse, false); 
client.BeginReceive(DataReceived, client); 

UdpClient server = new UdpClient(ConnectionSettings.soport); 
server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, false); 

然後從與server.Send的「服務器」套接字接收。

一旦我與插座完成,或關閉應用程序,它們被佈置的正是如此:

client.Client.Shutdown(SocketShutdown.Both); 
client.Client.Close(); 
client.Close(); 
client = null; 

server.Client.Shutdown(SocketShutdown.Both); 
server.Client.Close(); 
server.Close(); 
server = null; 

出於某種原因,如果我嘗試重新創建這些插座,通過創建套接字再次或重新啓動應用程序,我得到一個異常:

System: Only one usage of each socket address (protocol/network) is normally permitted. 

我明白這是因爲即使我關閉套接字,底層的Windows插座周圍徘徊,因爲Windows是讓他們活着......

我想使用相同的端口號,並且每次都重新創建套接字。我怎樣才能做到這一點?如果這是不可能的(如果你問我......這聽起來像是Windows中的一個網絡問題),那麼是否有一種方法可以重新獲取我使用的套接字?

+0

沒有一個可靠地再現問題的好的[mcve],就不可能知道什麼是錯的。但請放心,您不需要調用'SetSocketOption()'來讓事情順利進行。還要注意,你不應該在UDP套接字上調用'Shutdown()'。這是面向連接的套接字。我沒有測試過自己,但可能是'Shutdown()'導致延遲狀態並導致錯誤消息。 –

+0

_「我爲每個傳輸使用一個套接字,一個用於接收:」_ - 這對測試目的而言是很好的,即將兩個端點放在同一個程序中。但否則,不要。一個套接字可以接收和發送。如果你想在同一個程序中使用兩個端點,或者甚至在同一臺計算機上,那麼這些端點需要使用不同的端口號。不要試圖在具有相同端口#的同一臺計算機上製作多個套接字。 –

+0

我會嘗試刪除'Shutdown()',但是查看不應該導致問題的MDSN文檔...我應該更具體地介紹套接字:這是兩個不同的套接字,使用兩個不同的端口。一個是從端口X接收,另一個是在端口Y發送。整個'SetSocketOption'事情都沒有在那裏,這只是我試圖讓套接字正確釋放自己。我在其他操作系統中使用了完全相同的體系結構,沒有出現問題,所以這似乎更像是Windows處理這些事情的一個問題。 –

回答

0

我發現了這個問題。我的應用程序使用Process.Start(ProcessStartInfo pi)產卵進程。使用此函數時,屬於主應用程序進程(包括套接字)的所有句柄都由子進程繼承。

父進程終止時,該子仍處於活動狀態,保持套接字處於打開狀態。這可以通過兩種方式解決:

a)使用P/Invoke,將Process.Start替換爲createprocess(),將bInheritHandles設置爲false。據我所知,dotNet Process.Start函數沒有任何等價物,在我看來這是一個疏忽。

b)使用的P/Invoke,創建每個插座後,你不希望子進程繼承,調用SetHandleInformation()INHERIT作爲dwMask參數,NONE作爲dwFlags參數。

相關問題