2011-08-17 62 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