2011-08-17 69 views
2

我試圖創建一個自包含的類,它維護到服務器的TCP連接。TcpClient BottleNeck

我使用下列類變量:

TcpClient tcpClient; 
NetworkStream networkStream; 
BinaryReader mReader; 
BinaryWriter mWriter; 

並使用下面的代碼初始化它們:

tcpClient = new TcpClient(host, 443); 
networkStream = tcpClient.GetStream(); 
mReader = new BinaryReader(networkStream); 
mWriter = new BinaryWriter(networkStream); 

receiveMessage = new Thread(new ThreadStart(ReceiveMessages)); 
receiveMessage.Start(); 

我使用讀阻塞調用。每個來自服務器的數據包都以4個字節(一個int)作爲前綴,用於定義確切的數據包大小。我使用的是一個名爲ByteBuffer的類,它有一個List(Byte)來存儲字節。類有一些函數,它們使用ReadInt(),ReadString ()等,根據服務器協議。

這裏是接收器線程:

private void ReceiveMessages() 
{ 
    while (tcpClient.Connected) 
    { 
     if (tcpClient.Available >= 4) 
     { 
      try 
      { 
       ByteBuffer message = new ByteBuffer(); 
       message.AddBytes(mReader.ReadBytes(4)); 
       int mSize = message.ReadInt(); 
       message.AddBytes(mReader.ReadBytes(mSize - 4)); 
       MessageProcessor.Process(message); 
      } 
      catch (Exception ex) 
      { 
       Print(ex.Message); 
      } 
     } 
     Thread.Sleep(1); 
    } 
    Print("Receiver thread terminated."); 
    Reconnect(); 
} 

作爲參考,MessageProcessor的是一個靜態類看起來在分組信息並響應服務器適當。

我的問題是,當連接上的流量開始變得非常高時,響應開始顯着延遲。我想知道,就tcp連接而言,我是否做了錯誤的操作?我應該嘗試寫一個類的異步版本嗎? C#List對象是否太慢而無法經常使用(在ByteBuffer中)?

這實際上是我第一次嘗試網絡編程,所以任何建議都會非常有幫助。

謝謝。

+0

稍候...你不能只從BinaryReader在讀取的MReader整數直?爲什麼你需要一個ByteBuffer消息? BinaryReader文檔:http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx –

+0

我相信服務器使用big-endian,而BinaryReader使用little-endian。或者以其他方式。我不記得哪個。 – jjw

+0

好的。如果是這樣的話,那麼我沒有看到你正在做的事情有什麼錯誤。如果你想保持這個單線程,我建議使用一個Profiler來幫助找出放慢速度的地方。如果你的MessageProcessor。進程(消息)需要一些處理時間,我建議去多線程。 –

回答

1

我會重寫你ReceiveMessages方法,像這樣 刪除了Thread.Sleep這是壞的。使用更快的字節數組。

像@ jgauffin說異步網絡代碼好多了,但它更容易搞砸了。如果您剛剛開始使用網絡編程,請將其保持簡單。

我希望這對你更好。

注意的消息是沒有4字節的包頭

private void ReceiveMessages() 
    { 

     while (tcpClient.Connected) { 
      try { 

       var networkstream = tcpClient.GetStream(); 
       var header = new byte[4]; 
       networkstream.Read(header, 0, 4); 

       int len = 0; 
       // calculate length from header 
       // Do reverse for BigEndian, for little endian remove 
       Array.Reverse(header); 
       len = BitConverter.ToInt32(header, 0); 

       var message = new byte[len]; 
       networkstream.Read(message, 0, message.Length); 

       // Process message 

      } 
      catch (Exception ex) 
      { 
       Print(ex.Message); 
       // Exit loop something went wrong 
       break; 
      } 
     } 

     Print("Receiver thread terminated."); 
     Reconnect(); 

    } 
+0

感謝您的代碼,我會盡快嘗試。 Thread.Sleep()在那裏,因爲沒有它,程序正在使用CPU的重要部分。有沒有其他方法可以避免這種情況? – jjw

+0

在這個代碼networkstream.Read將阻塞,直到有足夠的字節可用,所以不需要Thread.Sleep –

+0

哦,我錯過了你刪除檢查可用字節。這比我所做的更有意義。謝謝 – jjw