2012-07-21 37 views
3

我正在用C#編寫一個聊天服務器,自下而上。「廣播」到TCP客戶端列表的最快方法

這就像一個大房間,所有的客戶,然後你可以發起私人聊天。我還將代碼放在了多個房間的未來整合中(但現在不需要)。

它的寫作主要是爲了好玩,但也因爲我要爲像我這樣的年輕人制作新的聊天室,因爲丹麥沒有人離開這裏。

我剛剛用170個客戶端進行了測試(使用JQuery和Flash橋寫入套接字連接)。發送給它的消息在本地網絡上的響應時間不到1秒。但現在我正在考慮能夠從中擠出什麼樣的表現。

我可以看到,如果我連接兩個客戶端,然後再連接其他客戶端,然後在客戶端2上寫入並觀察客戶端1,它立即出現在客戶端1上。CPU使用率和RAM使用率根本不顯示服務器壓力的跡象。它處理得很好,我認爲它可以擴展到至少1000 - 1500,沒有絲毫問題。

但是我注意到了一些事情,那就是如果我再次打開170個客戶端並在客戶端1上發送消息並在客戶端170上觀察,則會有大約750毫秒左右的日誌。 我知道這個問題,也就是說,當服務器收到一條聊天消息時,它會將它廣播給服務器上的每個客戶端。但是,它需要枚舉所有這些客戶端,並且需要時間。現在的延遲對於聊天來說是非常可以接受的,但我擔心客戶端1發送給客戶端750可能(尚未測試)需要2 - 3秒。而且,當我開始收到每秒2-3條信息時,我也很擔心。

所以總結起來,我想加快服務器的廣播過程。我已經在使用一個並行的foreach循環,而且我也使用異步套接字。

這裏是廣播代碼:

lock (_clientLock) 
     { 
      Parallel.ForEach(_clients, c => 
      { 
       c.Value.Send(message); 
      }); 
     } 

這裏是正在調用的每個客戶端上的發送功能:

try { 
     byte[] bytesOut = System.Text.Encoding.UTF8.GetBytes(message + "\0"); 
     _socket.BeginSend(bytesOut, 0, bytesOut.Length, SocketFlags.None, new AsyncCallback(OnSocketSent), null); 
     } 
     catch (Exception ex) { Drop(); } 

我想知道是否有什麼辦法可以加快這個嗎? 我已經考慮寫一些幫助類接受消息在一個隊列中,然後使用大概20個線程左右來拆分廣播列表。

但我想知道你對這個話題的看法,我是一名學生,我想學習! (:

順便說一句,我喜歡當你的代碼在發佈到堆棧溢出時發現問題。我現在使用重載函數接受來自服務器類的字節數組,所以UTF- 8轉換隻需要發生一次,同時爲了安全起見,字節數組長度的計算現在只發生一次,參見下面的更新版本 但我仍然對改進這種方法感興趣!

更新的廣播功能:

lock (_clientLock) 
     { 
      byte[] bytesOut = System.Text.Encoding.UTF8.GetBytes(message + "\0"); 
      int bytesOutLength = bytesOut.Length; 
      Parallel.ForEach(_clients, c => 
      { 
       c.Value.Send(bytesOut, bytesOutLength); 
      }); 
     } 

客戶對象上更新發送功能:

public void Send(byte[] message, int length) 
    { 
     try 
     { 
      _socket.BeginSend(message, 0, length, SocketFlags.None, new AsyncCallback(OnSocketSent), null); 
     } 
     catch (Exception ex) { Drop(); } 
    } 
+1

+1 Good and consise question。 – rcdmk 2012-07-21 22:33:34

回答

3

〜1秒的聲音真的慢於本地網絡。平均LAN延遲爲0.3ms。 Nagle是啓用還是禁用?我猜它已啓用...所以:改變(Socket.NoDelay)。那確實是,這意味着你必須承擔責任,不要以過分分散的方式寫入套接字 - 當然,所以不要逐字逐句滴答信息。組裝消息發送(或更好:多個未完成的消息)在內存中,並將其作爲一個單元發送。

+0

Nagle算法現在通過Socket.NoDelay()禁用。我不知道它是否有幫助,也許有一點。我仍然懷疑列舉客戶是一個問題。 消息已經被一次性發送。它們是JSON編碼字符串,當我調用廣播時,它總是一個完整的消息(因此附加一個0字節作爲消息分離)。 無論如何,不​​管是什麼原因造成的,我都是在加速提示之後,也是爲了學習。併發性和性能都是非常棒的主題! – Henrik 2012-07-21 22:43:27

+0

嗯我開始認爲這也是關於在同一臺PC上運行所有執行Javascript的多個瀏覽器。我開始深入代碼,我的服務器顯示2毫秒來枚舉客戶端和brodcast消息。我將開始進一步調查。 – Henrik 2012-07-21 23:12:45