2011-04-04 50 views
2

我有一個C#程序有很多(比方說大約一千個)打開了TcpClient對象。我想進入一個狀態,等待任何這些連接發生。處理多個TcpClient連接而不使用線程

我寧願不爲每個連接啓動一個線程。

喜歡的東西...

while (keepRunning) 
{ 
    // Wait for any one connection to receive something. 
    TcpClient active = WaitAnyTcpClient(collectionOfOpenTcpClients); 

    // One selected connection has incomming traffic. Deal with it. 
    // (If other connections have traffic during this function, the OS 
    // will have to buffer the data until the loop goes round again.) 
    DealWithConnection(active); 
} 

附加信息:
的TcpClient的對象來自的TcpListener。
目標環境將是MS .NET或Mono-on-Linux。
該協議在連接打開時要求長時間閒置。

+1

在Unix世界中,您將使用'select'系統調用來執行此操作。我確定Windows中有一些模擬。 – 2011-04-04 17:02:31

+1

你對「每個連接的線程」的假設是有缺陷的。線程池與APM方法結合是解決這類問題的方法。只有幾個線程可以爲許多客戶提供服務。我給了這個答案應該證明內容豐富:http://stackoverflow.com/questions/3153959/how-does-a-full-featured-long-polling-server-work-abstractly/3154115#3154115 – spender 2011-04-04 17:11:42

+0

@spender - 你建議我BeginRead all〜1000 TcpClients並處理回調中的任何流量?如果你想把它寫成答案,我會接受它。 – billpg 2011-04-04 17:24:09

回答

2

您試圖做的是在Microsoft術語中稱爲異步模式。總體思路是將所有I/O阻塞操作改爲非阻塞操作。如果這樣做了,那麼應用程序通常需要的系統線程數量與機器上的CPU核心數量一樣多。

以.NET 4的看看任務並行庫: http://msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx

它是在普通的舊開始/回撥/語境下的.Net模式相當成熟的包裝。

更新:

想想你從連接讀取之後什麼您將與數據做。在現實生活中,您可能必須回覆客戶端或將數據保存到文件中。在這種情況下,您將需要一些C#基礎結構來包含/管理您的邏輯並仍然保留在單個線程中。 TPL免費提供給你。它唯一的缺點是它是在.Net 4中引入的,所以它可能不是Mono。

要考慮的另一件事是連接的一生。您的連接打開/關閉的頻率以及他們居住多久?這很重要,因爲接受和斷開TCP連接需要與客戶端進行數據包交換(本質上是異步的,而且 - 惡意客戶端可能根本不會返回ACK(已知)數據包)。如果你認爲這個方面對你的應用程序很重要,你可能想研究如何在.Net中正確處理這個問題。在WinAPI中相應的功能是AcceptEx和DisconnectEx。可能它們被包裝在.Net中,用Begin/End方法 - 在這種情況下,你很好走。否則,你可能不得不通過這些WinAPI調用創建一個包裝。