NetworkStream.read 从流中读取数据需要 2 秒 (TCP C#)

NetworkStream.read taking 2 seconds to read data from stream (TCP C#)

我在与服务器通信的 C# 中有一个 TCP 请求响应模型。服务器将数据写入流后,我正在读取该数据。但是 stream.read 需要 2 秒来读取数据。我需要在 2 秒内向服务器发送明确的确认,但由于读取数据所花费的时间而无法这样做。 下面是我读取数据的代码:

            byte[] resp = new byte[100000];
            var memoryStream = new MemoryStream();
            int bytes;

            String timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("Before reading data: ");
            Console.WriteLine(timeStamp);

            do
            {
                bytes = stream.Read(resp, 0, resp.Length);
                memoryStream.Write(resp, 0, bytes);
                               
            }
            while (bytes > 0);

            timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("After reading data: ");
            Console.WriteLine(timeStamp);

            
            GenerateAcknowledgemnt(stream);


            timeStamp = GetTimestamp(DateTime.Now);
            Console.WriteLine("After sending ack: ");
            Console.WriteLine(timeStamp);


以下是读取的时间戳,格式为 yyyyMMddHHmmssff:

读取数据前: 2022050615490817

读取数据后: 2022050615491019

发送确认后: 2022050615491020

我已将秒标记为粗体。

如何减少 stream.read 阅读的时间?我也尝试将网络流包装在 BufferedStream 中,但没有帮助。

目前,您正在执行一个读取循环,一直持续到 Read returns 一个 non-positive 数字;在 TCP 中,这意味着您要等到另一端 挂断 (或至少挂断他们的出站套接字),直到您退出该循环。我怀疑正在发生的事情是另一端放弃你,关闭他们的连接,然后你才脱离循环。

基本上:你不能那样循环;相反,您需要做的是仔细阅读直到或者 EOF (bytes <= 0) 或者 直到你至少有一个完整的框架可以响应,在后一种情况下:响应 then。这通常意味着循环更像 (pseudo-code):

while (TryReadSomeMoreData()) // performs a read into the buffer, positive result
{
    // note: may have more than one frame per successful 'read'
    while (TryParseOneFrame(out frame)) 
    {
        ProcessFrame(frame); // includes sending responses
        // (and discard anything that you've now processed from the back-buffer)
    }
}

(在这里解析一个帧意味着:遵循关于从流中隔离单个消息的任何规则——这可能意味着寻找一个标记值,例如 CR/LF/NUL,或者可能意味着检查你是否有足够的字节读取包含长度的 header,然后检查您是否有 however-many 字节 header 指示为有效负载)

如果您使用 MemoryStream 作为积压工作,这 有点 尴尬,因为丢弃步骤不方便; “管道”API 更专门为此设计,但是:任何一种方式都可以工作。

其次:您可能更喜欢异步 IO,尽管同步 IO 可能适合只有一个连接的简单客户端应用程序(但不适用于可能有很多连接的服务器)。