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 可能适合只有一个连接的简单客户端应用程序(但不适用于可能有很多连接的服务器)。
我在与服务器通信的 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 可能适合只有一个连接的简单客户端应用程序(但不适用于可能有很多连接的服务器)。