2010-10-01 239 views
2

我想優化TCP套接字包裝物,有很多的入站連接的掙扎。我在一個基本的聊天服務器和一個小客戶端應用程序中測試它,以便將客戶端發送給它。這兩個應用程序都位於由千兆交換機連接的單獨的W2k3服務器上。Socket.SendAsync服用幾秒鐘完成

通過試驗和錯誤,我改進我的測試,以10個客戶在100周毫秒的時間間隔連接,那麼一旦所有10個連接它們每一個發送達到100MS間隔「入室」消息給服務器,再一次。當服務器收到一條消息時,它會向房間中的每個人列表回覆發件人,並向房間中的其他人發送消息,告訴他們新的到來。

每個發送都需要1秒鐘才能完成(這對於100多個客戶端來說會持續3-4秒),並且通過日誌記錄,我已經確定延遲在Socket.SendAync和相應的事件發生之間。整個Cpu使用率始終很低。

我用盡了一切我能想到的,並花了幾天尋找線索在線和我在一個完全喪失。這不可能是正常的嗎?

編輯:代碼按要求。我已經整理了一下,刪除了不相關的計數器和日誌記錄等,現在它已經在黑客攻擊之上破解了,因爲我試圖縮小這個問題的範圍。

private void DoSend(AsyncUserToken token, String msg) 
    { 
     SocketAsyncEventArgs writeEventArgs = new SocketAsyncEventArgs(); 
     writeEventArgs.Completed += ProcessSend; 
     writeEventArgs.UserToken = token; 
     Byte[] sendBuffer = Encoding.UTF8.GetBytes(msg + LineTerminator); 
     writeEventArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length); 

     Interlocked.Add(ref m_totalBytesAttemptedSend, sendBuffer.Length); 
     Logger2.log(Logger2.Debug5, token.ConnectionId, "Total Bytes attempted: " + m_totalBytesAttemptedSend); 

     bool willRaiseEvent = true; 
     try 
     { 
      willRaiseEvent = token.Socket.SendAsync(writeEventArgs); 
     } 
     catch (Exception e) 
     { 
      Logger2.log(Logger2.Debug2, token.ConnectionId, e.Message); 
      writeEventArgs.Dispose(); 
     } 
     if (!willRaiseEvent) 
     { 
      ProcessSend(null, writeEventArgs); 
     } 
    } 


    private void ProcessSend(Object sender, SocketAsyncEventArgs e) 
    { 
     AsyncUserToken token = (AsyncUserToken)e.UserToken; 
     Logger2.log(Logger2.Debug5, token.ConnectionId, "Send Complete"); 
     if (e.SocketError == SocketError.Success) 
     { 
      Interlocked.Add(ref m_totalBytesSent, e.BytesTransferred); 
      Logger2.log(Logger2.Debug5, ((AsyncUserToken)e.UserToken).ConnectionId, "Total Bytes sent: " + m_totalBytesSent); 

     } 
     else 
     { 
      if (token.Connected) 
      { 
       CloseClientSocket(token); 
      } 
     } 
     e.Dispose(); 
    } 
+0

你能發表一些相關的代碼嗎?猜測套接字問題是非常困難的。 – 2010-10-01 16:37:40

+0

你有一個SocketAsyncEventArgs池嗎? – 2010-10-01 19:59:28

+0

埃裏克 - 我目前沒有彙集SocketAysncEventArgs,但計劃稍後添加。不過,我在創建SocketAysncEventArgs並填充其緩衝區並將結束時間記錄爲回調中的第一個操作之後記錄了開始時間,因此,雖然我知道它的低效率,但它不應該影響此部分執行? – Adster 2010-10-04 09:24:44

回答

1

您在每個連接上發送了多少數據,並且您發送速度有多快?

通常是異步發送需要很長的時間才能完成的原因是,你填寫的TCP窗口(見here瞭解詳細信息)和本地TCP堆棧無法發送任何數據,直到它得到一些的ACK從對等。如果您繼續發送數據,那麼您只是在網絡子系統中本地排隊,因爲堆棧不允許發送它。由於擁塞和數據包丟失,這可能會變得更糟,因爲傳輸中的數據需要更長的時間才能到達對端,並且ACK需要更長的時間才能恢復...

如果是這種情況(以及諸如WireShark之​​類的工具應該使您能夠看到窗口大小更新和零窗口情況等),那麼增加連接的窗口大小可能會有所幫助(請參閱here)。

如果協議中沒有明確的流量控制,則上述情況更可能發生。最好在協議設計中包含某種形式的顯式流量控制,恕我直言,以避免這種情況。

這也是明智的包括一些這方面的發送端的保護作爲一個無界的發送者可以通過內存非常迅速咀嚼。我使用過的一種方法很好用,就是有一個隊列,可以將出站數據放入隊列中,並根據先前發送的發送完成情況實際發送此隊列中的數據(請參閱here)。

+0

感謝Len,我會安裝wireshark以查看它是否會散發出任何光。同時,我已經讀取了第一次發送完成時(在我打電話給SendAsync後1.2-1.3秒)傳輸的數據的一些讀數,並且它確實數量很小,所以我不相信這是問題所在。 成功發送的總字節數:40(1發送) 收到的總字節數:827(10收到) 嘗試發送的總字節數:250(4發送) – Adster 2010-10-04 09:13:27

+0

嗯,聽起來不像是問題所在。這通常在發送大量數據時顯示 – 2010-10-04 10:16:55

1

嘗試使用socket.NoDelay=True;。 默認值爲No這意味着基礎堆棧會在實際發送之前嘗試累積傳輸。