C# TCP客户端瓶颈

C# TCP客户端瓶颈,c#,C#,我正在尝试创建一个自包含类,它维护到服务器的Tcp连接 我正在使用以下类变量: TcpClient tcpClient; NetworkStream networkStream; BinaryReader mReader; BinaryWriter mWriter; 并使用以下代码初始化它们: tcpClient = new TcpClient(host, 443); networkStream = tcpClient.GetStream(); mReader = new BinaryRead

我正在尝试创建一个自包含类,它维护到服务器的Tcp连接

我正在使用以下类变量:

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的类,它有一个列表(字节)来存储输入的字节。根据服务器协议,该类具有使用ReadInt()、ReadString()等从字节列表顶部提取int和其他类型的函数

以下是接收器线程:

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中)

这是我第一次尝试网络编程,所以任何建议都会非常有用


谢谢。

改用异步处理。使用线程和
线程。睡眠
是邪恶的

看看你的情况


您也可以使用我的新库:

我会像这样重写您的ReceiveMessages方法 删除线程。睡眠不好。使用更快的字节数组

正如@jgauffin所说,异步网络代码更好,但更容易出错。如果你刚刚开始网络编程,最好保持简单

我希望这对你更有效

注意:消息没有4字节的标题


等待你不能直接从二进制读取器mReader读取一个整数吗?你为什么需要ByteBuffer留言?BinaryReader文档:我相信服务器使用big-endian,BinaryReader使用little-endian。或者其他方式。我不记得是哪个了。如果是这样的话,那么我看不出你所做的有什么真正的错误。如果您想保持单线程,我建议使用探查器来帮助您找出速度减慢的地方。如果您的MessageProcessor.Process(message)需要一些处理时间,我建议您使用多线程。仅供参考,这篇文章似乎表明列表本质上是一个固定数组:因此使用列表对于线程来说是很好的选择,这让我对使用列表感觉更好。我使用了一个分析器,但似乎找不到代码在哪里受阻。它的大部分时间都花在“if(tcpClient.Available>=4)”这一行上,我认为这只是数据包之间的时间。我知道它速度变慢的唯一原因是,当我查看它发送的响应(在使用服务器的应用程序中)时,我看到它们的延迟时间为3-4秒。我想发送功能可能会有一些问题,但发送的使用频率较低(2包/500毫秒)。感谢您的代码,我会尽快尝试一下。Sleep()就在那里,因为没有它,程序会占用很大一部分CPU。是否有其他方法可以避免此问题?在此代码网络流中。Read将阻止,直到有足够的字节可用,因此不需要Thread.SleepOh,我错过了您删除检查可用字节的步骤。这比我现在做的更有意义。ThanksI尝试删除行以检查是否有4个字节可用,并删除了睡眠,我得到以下异常:“无法从传输连接读取数据:阻塞操作被对WSACancelBlockingCall的调用中断。”知道我做错了什么吗?我需要查看完整的程序才能回答。我猜发生这种情况是因为您与线程外部的套接字交互,或者是由于外部因素(从服务器断开的链接)。更完整的代码将负责TcpSocket上的同步(锁定-这是一种简单的方法),或者如果线程中只需要TcpClient,则应将TcpSocket的初始化放在ReceiveMessages中。如果您使用相同的套接字发送消息,那么在同一线程中发生的情况最好。
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();

    }