2011-03-06 27 views
0

我遇到了很多AsyncSends與幾十個客戶端套接字進行的問題,此刻如果任何遠程客戶端停止接收但實際上並沒有斷開連接,該應用程序很快就吃掉了所有的SocketAsyncEventArgs(又名sae),因爲SendAsync沒有完成,所以我沒有預先分配它們。對此的明顯解決方案是實現每客戶端發送隊列,這聽起來很容易,但我不清楚具體細節。我爲每個客戶端分配了一個sae,這是完美的,理想情況下,我希望爲客戶端的異步發送分配一個sae。遠程客戶端停止接收時的Socket.AsyncSend行爲

據我所知,彈出窗口並詢問一個隱含的「給我代碼」解決方案請求的問題是看不起來的,但我真的無法提出很多,無論是.XAsync方法,微軟對於一般的發送隊列來說是一個可怕的例子。

編輯@ J.N。

我忘了提及它,但我-am-實際上使用一堆預分配的sae存儲在一個內部使用ConcurrentBag的管理類中。通過一個連接,在一個測試場景中,每秒發送20條小消息(稍微多於生產服務器中實際發送的消息數的兩倍),服務器在幾秒鐘內就會消耗500個預分配的sae。如果我實施「創建如果空的」代碼,那麼sae計數就會迅速攀升至數千。

我瞭解Socket類的異步方法提供的功能,但如果存在網絡打嗝或類似情況,此問題將在幾秒內徹底炸燬服務器。發送隊列聽起來像是一個很好的解決方案,但我不知道在高性能生產環境中執行是否是個好主意。

雖然基本問題仍然存在,即每個客戶端每秒發送十幾條消息,任何網絡擁塞或滯後於連接但不斷開連接的其他因素將迅速惡化爲一個滯後的混亂。

我認爲我可能尋找的解決方案是鎖定用於發送的單個sae,直到達到完成回調,然後sae被解鎖,然後重新使用以發送任何未決數據。但它的實際執行情況卻讓我無法迴避。

回答

0

在開始閱讀之前,請確保您已經玩過並瞭解了Socket.SendTimeout

我建議兩種不同的方法:

  • 首先,你可以用SAE池嘗試。最好的課程是ConcurrentBag(我想你需要線程安全)。我們爲我公司的一個緩衝池做了這個工作,我們在ConcurentBag周圍做了一個小包裝,如果碰巧池空了,就會創建新的對象。在你的用例中,你應該考慮斷開客戶端。當然你需要爲每個連接有一個這樣的池,所以我建議使用在套接字上索引的字典。這有點醜,但它的工作原理。其次,你可以實現你自己的發送隊列,但是你會複製.Net中的異步功能(並且可能會讓它變得更糟)。你需要你自己的線程和一個隊列(一個同步的)消息來發送。當你做一個發送時,你需要將你的消息推送到隊列中。後臺發送將定期檢查隊列的狀態,如果不是空的,則彈出一些消息並同步發送。我建議在每次添加隊列中的某些內容以喚醒後臺線程時使用AutoResetEvent。