2012-02-08 30 views
2

要清楚,我所指的所有TCPClients不是我自己的類的實例,它們都是System.Net.Sockets.TcpClient來自Mono的.NET 4.0實現。關閉System.Net.Sockets.TcpClient殺死同一IP地址的其他TCPClient的連接

我有一臺服務器正在偵聽客戶端連接,就像服務器一樣。每當它得到一個新的客戶端,它就創建一個新的TCPClient來處理新線程上的連接。我正在用字典跟蹤所有連接和線程。如果客戶端斷開連接,它將向服務器發送斷開連接消息,TCPClient關閉,字典條目被刪除,線程自然死亡。沒有大驚小怪,沒有麻煩。服務器可以毫無問題地處理多個客戶端。

但是,我模擬如果客戶端斷開連接,沒有機會發送斷開連接消息,然後重新連接會發生什麼。我正在檢測客戶端是否與用戶名系統重新連接(當我完成測試時它會更安全)。如果我只是創建一個新的TCPClient並讓舊的TCPClient運行,那麼系統工作的很好,但是我有一堆無用的線程,它們佔用了空間並且什麼也不做。懶蟲。

所以我嘗試關閉與舊連接關聯的TCPClient。當我這樣做,新的TcpClient也死了,客戶端程序將引發此錯誤:

E/mono (12944): Unhandled Exception: System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: The socket has been shut down 

而且服務器拋出這個錯誤:

Unable to write data to the transport connection: An established connection was aborted by the software in your host machine. 

Cannot read from a closed TextReader. 

因此收舊的TcpClient與遠程端點發言權:192.168.1.10:50001

而且打破了發言權的遠程端點新的TcpClient:192.168.1.10:50002

於是兩人的TcpClient對象具有相同的遠程端點IP地址,但具有不同的遠程端點端口。但關閉這個似乎阻止了另一個工作。我希望能夠關閉舊的TCPClient進行清理,而不關閉新的TCPClient。

我懷疑這與TCPClient如何在低級別的套接字下工作有關,但沒有任何真正的理解,我無法解決它。

+0

字典的關鍵是什麼?如果是用戶名,這似乎來自關閉錯誤的TCPClient – 2012-02-08 01:39:54

+0

好的想法,但我沒有添加新的連接到字典,直到衝突解決。我使用字典關閉舊連接,刪除字典條目,然後將新連接添加到字典。 – Excrubulent 2012-02-08 01:42:42

+0

另外,字典的關鍵確實是用戶名。 – Excrubulent 2012-02-08 01:46:12

回答

3

我在我的套接字服務器上有類似的問題。我使用了一個簡單的List來代替字典來保存當前所有的連接。在一個連續的while循環中偵聽新的流,我有一個try/catch,並且在catch塊中,如果它斷開連接,它會終止客戶端。

像這樣的事情在sever.cs:

public static void CloseClient(SocketClient whichClient) 
     { 
      ClientList.Remove(whichClient); 
      whichClient.Client.Close(); 
      // dispose of the client object 
      whichClient.Dispose(); 
      whichClient = null; 
     } 

,然後在客戶端上一個簡單的處理方法:

public void Dispose() 
     { 
      System.GC.SuppressFinalize(this); 
     } 

編輯:本貼是OP的決議,他或她在自己的代碼幫助下自己找到了。

所以要澄清的情況是,我有兩個對象的TcpClient和TCPClientA與TCPClientB不同的遠程終端端口,但相同的IP:

TCPClientA.Client.RemoteEndPoint.ToString(); 

回報:192.168.1。10:50001

TCPClientB.Client.RemoteEndPoint.ToString(); 

回報:192.168.1.10:50002

TCPClientA需要清理,因爲它不再是有用的,所以我叫

TCPClientA.Close(); 

但這關閉套接字的客戶端在TCPClientB的另一端,出於某種原因。但是,寫入

TCPClientA.Client.Close(); 
TCPClientA.Close(); 

成功關閉TCPClientA而不干擾TCPClientB。所以我解決了這個問題,但我不明白爲什麼它會這樣。

+0

謝謝克里斯託弗,我用我在閱讀代碼後發現的代碼編輯了我的問題。如果您想將我的代碼添加到您的答案中,我很樂意將其標記爲答案。不過,我現在不想,因爲你的代碼與我的代碼有點不同。首先,您使用的是SocketClient,TCPClient沒有Dispose()方法。另外,在我的代碼中不需要將whichClient設置爲null。 – Excrubulent 2012-02-08 06:13:52

+0

SocketClient是我寫的自定義類,或多或少只是TCPClient的擴展。但是,當然,我會把你的代碼移到我的答案上。 – 2012-02-08 15:41:25

+0

回答你爲什麼使用TCPClientA.Client.Close()工作的問題......很難說,因爲我們看不到你的類結構。我的假設是TCPClientA是一個名爲Client的屬性類,它是您的實際TcpClient。這正是我設置的方式,但我的類叫做SocketClient。我真的很驚訝TCPClientA.Close()爲你做了什麼(假設我對你的類結構的假設是正確的)。要真正關閉TcpClient,您必須通過您的成員列表鑽取該對象,這是我所做的,似乎爲您工作。 – 2012-02-08 15:52:58

0

這聽起來像是代碼中的錯誤。關閉一個入站連接不應該關閉另一個連接。

+1

它不會「關閉()」它,它只是導致它停止正常運行。如果它是代碼中的錯誤,你能解釋爲什麼調用TCPClientA.Client.Close();接着是TCPClientA.Close();修復了問題,只需調用TCPClientA.Close();本身導致問題?如果我關閉了錯誤的TCPClient,那麼這兩個操作都應該殺死錯誤的連接。前者不,後者確實如此。 – Excrubulent 2012-02-08 11:54:40

0

看起來您已經找到了一個解決方案,但您只需注意在.NET中編寫客戶端/服務器應用程序時存在許多類似的缺陷。有一個開放源代碼的網絡庫(完全支持單聲道),這些問題已經解決,networkComms.net。基本樣本是here

聲明:這是一個商業產品,我是創始人。