1

我正在尝试在屏幕上显示来自 ssl 流(来自网站)的任何数据。因为我不知道数据什么时候到达,所以我使用了另一个线程,它一直从流中读取,直到读取字节。这非常有效,但是,我的 CPU 使用率跃升至 25% 并保持在那里(最大使用率为 1 个线程,我的 PC 有 4 个线程)。虽然这确实有点道理,因为线程卡在了一个while循环中,但我没想到线程类的一个实例会消耗我的CPU的整个线程(我可以发誓这在使用简单的客户端时不会发生/服务器应用程序)。

一旦连接初始化,线程就开始运行,用户可以随时向网站发送数据,并且应用程序应该打印出响应。什么是替代解决方案?我应该放弃 SslStream 并开始使用其他东西吗?

这是在这个单独的线程上运行的代码:

    void ReadDataAsync(Object obj) {
        byte[] buffer = new byte[65536]; //65536, make sure all bytes can be
                                         //from a single packet
        int bytesRead = -1;

        while (true) {
            //It makes sense for sslStream.Read to block until bytes have been
            //read, but it doesn't.  Which is why I'm checking if bytesRead!=0

            bytesRead = sslStream.Read(buffer, 0, 65536);

            if (bytesRead != 0) {
                Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead));
                buffer = new byte[65536];
            }
        }
    }

谢谢大家,感谢您的帮助

编辑:
我尝试改用 BeginRead 和 EndRead,正如“gt”所建议的那样。为此,每当用户发送请求时,我都会使用 BeginRead。收到所有数据后,我将它们打印在屏幕上。这似乎工作正常,但我担心将来是否会有任何问题。数据包有没有可能弄乱?例如,是否有可能 EndRead 在第一个数据包的末尾没有返回 0 并且它继续读取第二个数据包?如果可能的话,我将如何继续解决这个问题?接收到的数据只是http层的body,所以无法事先访问IP层知道包的长度。

    public void SendData(byte[] message) {
        sslStream.Write(message);
        sslStream.Flush();

        //Start reading for response (if not already reading)
        if (sslStream.CanRead) {
            sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
        }
    }

    void ReadData(IAsyncResult ar) {
        int bytesRead = sslStream.EndRead(ar);

        if (bytesRead > 0) {
            //data may be on their way so start reading again
            message.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
            sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
            Console.WriteLine("Data received but more may be on their way...");
        } else {
            //All data arrived (Checking if length is more than 0 since all the
            //data may had already arrived in the previous check (above)
            if (message.ToString().Length > 0) {
                Console.WriteLine(message.ToString());
                //Clear StringBuilder and reset buffer.
                message.Clear();
                buffer = new byte[BufferSize];
            }
        }
    }

再次感谢

4

1 回答 1

1

看到while(true)通常是一个不好的迹象......如果您的代码进入没有结束条件的“紧密”循环,它将继续循环并消耗所有可用资源。

仔细检查“if”条件是否符合您的预期。例如,如果流在多个部分中被读取会发生什么?(例如 32768 的两部分)。这是完全可能的。

一旦你对这种行为感到满意,你可以强制线程在尝试下一个之前休眠一段时间Read,使用Thread.Sleep(100).

或者,尝试查看异步 IO,使用BeginRead. 请参阅MSDN 上的此示例


编辑,回答问题的第 2 部分:

我怀疑如果某事可能出错,它就会出错,所以要防御性地编码!下一个问题的解决方案是缓冲从流中读取的所有数据。然后让另一个线程尝试从缓冲区中读取整个数据包。不要忘记使用锁来防止同时读取/写入缓冲区。

为此编写单元测试也是一个好主意,以涵盖“碎片化”行为(以及正常行为)。

或者,您也许可以研究为您处理这些事情的更高级别的协议。我经常看到提到的是 Google 的Protocol Buffers

于 2013-03-25T14:57:22.920 回答