代碼是參考https://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs(v=vs.110).aspx寫的
服務端Listen數2000
找了一個TCP客戶端測驗工具創建了2000個客戶端同時連接服務端并發送資料,過幾秒鐘后全部斷開,這樣反復7、8次后續客戶端就連接不上服務端了。
netstat 里看到服務端還是處于監聽狀態的 TCP 127.0.0.1:20000 0.0.0.0:0 LISTENING
請問下該怎么排查這個問題?或者說會有哪些操作會導致這個問題?
uj5u.com熱心網友回復:
服務端也沒有做,客戶端斷開處理。socket服務端在客戶端斷開后5-10中還是處于連接狀態。所以導致2000客戶端重連時會失敗!uj5u.com熱心網友回復:
看下是不是有大量 沒有完全斷開的連接uj5u.com熱心網友回復:
你可以先用工具,或程式里自我檢查一些除錯資料,比如記憶體占用,執行緒數量,執行緒池下的作業執行緒數和IOCP執行緒數,等等。還可以考慮,把m_maxNumberAcceptedClients換成SemaphorSlim,它支持查看當前信號占用數。
如果信號占用數沒有被釋放,就可能導致m_maxNumberAcceptedClients.WaitOne();阻塞,從而導致沒有繼續下一個接收,客戶端就連接不上服務端了。
如果ProcessReceive和ProcessSend里面有代碼拋出例外,就會導致CloseClientSocket(e);沒有機會得到呼叫,就可能導致該連接的信號占用數就沒有被釋放。
uj5u.com熱心網友回復:
服務端要做斷開檢測的,比如寫入例外,就表示斷開了,此時要把服務端連接釋放掉,否則會影響后邊的連接。uj5u.com熱心網友回復:
服務端看下 netstat各種狀態的連接資料量,客戶端也用netstat看下連接狀態,
懷疑連接占滿了
uj5u.com熱心網友回復:
TCP 連接會話在斷開后,主動斷開的一方會進入 timewait 狀態,持續 120-240 秒(依據作業系統),在此期間這個會話的源埠號(隨機埠)不可用,直到該埠號被釋放(參見《TCP-IP詳解》一書)。你的客戶端建立 TCP 連接太頻繁了,壓力測驗應使用多個客戶端機器來模擬,而不是一個。可以使用 netstat 命令查看網路會話狀態。
uj5u.com熱心網友回復:
確實是這個信號量的問題,我剛剛用SemaphoreSlim看了下,每一次重連都會增加占用數。ProcessReceive和ProcessSend似乎沒有拋例外。查了下是CloseClientSocket里的token.Socket.Close();拋了例外導致信號量沒釋放,token=null。當客戶端數量大于服務端監聽的數量時好像就會出現這個問題,在ProcessAccept里AcceptSocket.RemoteEndPoint也是null,拋了例外導致信號量沒釋放。請教一下在ProcessAccept里AcceptSocket.RemoteEndPoint=null的情況下怎么做處理比較合適?直接return也會導致信號量沒釋放uj5u.com熱心網友回復:
類似如此?try
{
}
catch(...)
{
CloseClientSocket(e);
}
或者如果邏輯適合,就放finally塊下?
uj5u.com熱心網友回復:
如果CloseClientSocket(e);會拋例外,那就類似如下代碼?private void CloseClientSocket(SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
// close the socket associated with the client
try
{
token.Socket.Shutdown(SocketShutdown.Send);
token.Socket.Close();
}
// throws if client process has already closed
catch (Exception) { }
finally // <----
{
// decrement the counter keeping track of the total number of clients connected to the server
Interlocked.Decrement(ref m_numConnectedSockets);
// Free the SocketAsyncEventArg so they can be reused by another client
m_readWritePool.Push(e);
m_maxNumberAcceptedClients.Release();
}
Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);
}
uj5u.com熱心網友回復:
我估計是你客戶端全部斷開后 服務器端得連接 仍然沒有斷開, 你可以嘗試定義一個斷開連接的請求,通知服務端銷毀連接uj5u.com熱心網友回復:
我用netstat -ano 看服務端處于監聽狀態,然后客戶端一個都沒uj5u.com熱心網友回復:
客戶端關閉后,我用netstat -ano看到服務端處于監聽狀態,然后串列里是沒有客戶端。這連接應該是斷干凈了吧?uj5u.com熱心網友回復:
我在ProcessAccept里最前面加了判斷if (e.AcceptSocket.RemoteEndPoint == null)試了幾次似乎沒什么問題.....我沒怎么搞明白當一個異步連接觸發時為什么有時候RemoteEndPoint是null,這種情況出現在客戶端同時連接數大于服務端監聽時。然后同時關閉全部客戶端時會出現RemoteEndPoint是null
{
m_maxNumberAcceptedClients.Release();
StartAccept(e);
return;
}
uj5u.com熱心網友回復:
你應該看客戶端,不是服務端。
uj5u.com熱心網友回復:
客戶端關閉后,我用netstat -ano看到服務端處于監聽狀態,然后串列里是沒有客戶端。這連接應該是斷干凈了吧? TCP 連接會話在斷開后,主動斷開的一方會進入 timewait 狀態,持續 120-240 秒(依據作業系統),在此期間這個會話的源埠號(隨機埠)不可用,直到該埠號被釋放(參見《TCP-IP詳解》一書)。你的客戶端建立 TCP 連接太頻繁了,壓力測驗應使用多個客戶端機器來模擬,而不是一個。
可以使用 netstat 命令查看網路會話狀態。
你應該看客戶端,不是服務端。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/16242.html
標籤:C#
下一篇:C# 繪制時頻圖
