C# NetworkStream.DataAvailable 似乎不可靠 [英] C# NetworkStream.DataAvailable seems to be unreliable

查看:24
本文介绍了C# NetworkStream.DataAvailable 似乎不可靠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,它使用 TCP 套接字来交换在大多数情况下包含 JSON 字符串数据的字节数组.我所经历的是,对于较大的消息和不太理想的网络条件,使用 NetworkStream.DataAvailable 似乎不是检测消息结束的可靠方法.似乎在某些情况下 DataAvailable 设置为 false 即使只有部分消息已由对等方传输(使用 TcpClient.GetStream().Write(data, 0, data.Length). 这会导致将不完整的数据传回应用程序,在 JSON 消息的情况下,这意味着反序列化失败.

I have an app that uses a TCP socket to exchange byte arrays which in most cases contain JSON string data. What I'm experiencing is that, for larger messages and less than ideal network conditions, use of NetworkStream.DataAvailable does NOT seem to be a reliable way to detect an end of message. It seems that in some cases DataAvailable is set to false even when only part of the message has been transmitted by peer (which is using TcpClient.GetStream().Write(data, 0, data.Length). This results in incomplete data being passed back to the app, which in the case of a JSON message, means deserialization fails.

我尝试了两种表现出相同问题的实现:

I've tried two implementations which exhibit the same issue:

实施 1:

byte[] Data;
byte[] buffer = new byte[2048];
using (MemoryStream ms = new MemoryStream())
{
    int read;

    while ((read = ClientStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        ms.Write(buffer, 0, read);
        BytesRead += read;

        if (!ClientStream.DataAvailable) break;
    }

    Data = ms.ToArray();
}

实现 2:

byte[] Data;
using (MemoryStream ms = new MemoryStream())
{
    byte[] buffer = new byte[2048];

    do
    {
        int read = ClientStream.Read(buffer, 0, buffer.Length);
        if (read > 0)
        {
            ms.Write(buffer, 0, read);
            BytesRead += read;
        }
    }
    while (ClientStream.DataAvailable);

    Data = ms.ToArray();
}

似乎一种非常有效但完全次优的解决方案是添加 Thread.Sleep 以防 NetworkStream.DataAvailable 为 false(在循环内时)以允许传递数据.然而,这严重限制了我想避免的整体 IOPS,即

It seems one solution that works really well but is completely sub-optimal is to add a Thread.Sleep in case NetworkStream.DataAvailable is false (while inside the loop) to allow data to be delivered. However this severely limits overall IOPS which I would like to avoid, i.e.

实现 3(有效,但不理想)

Implementation 3 (works, but suboptimal)

byte[] Data;
using (MemoryStream ms = new MemoryStream())
{
    byte[] buffer = new byte[2048];

    do
    {
        int read = ClientStream.Read(buffer, 0, buffer.Length);
        if (read > 0)
        {
            ms.Write(buffer, 0, read);
            BytesRead += read;
        }

        if (!ClientStream.DataAvailable) System.Threading.Thread.Sleep(250);
    }
    while (ClientStream.DataAvailable);

    Data = ms.ToArray();
}

我真的很想找到一种方法来保持循环直到所有数据都被交付.正如我提到的,我正在对客户端进行从零到数据长度的简单写操作,所以我不认为那里有问题.

I'd really like to find a way to remain in the loop until all of the data is delivered. As I mentioned, I'm doing a simple write operation on the client from zero to data length, so I'm not thinking there is an issue there.

有没有人有过这样的经历和推荐?

Has anyone had any experience like this before and a recommendation?

推荐答案

看来 .DataAvailable 确实可靠,而且由于数据通过网络到达的速度可能比从流中读取数据的速度慢,因此 .DataAvailable 可以我的应用程序认为是一条消息的开始和结束之间的触发器.

It seems .DataAvailable is indeed reliable and that, since the data arrives over the network potentially at a rate slower than data is read from the stream, .DataAvailable can flip-flop between the start and end of what my application thinks is a message.

我正在回答并关闭此问题,因为我认为唯一的解决方案是:

I'm answering and closing this as I believe the only solutions to this are:

1) 添加一个总体接收超时值,并在读取循环中执行一个thread.sleep,并在到达接收超时后使操作过期

1) add an over-arching receive timeout value, and perform a thread.sleep in the read loop, and expiring the operation once the receive timeout is reached

2) 实现一些指示数据有效负载大小的机制——明确地或通过创建元数据头系统——来指示应该读取多少数据,并在读取了这么多数据或操作超时后退出

2) implement some mechanism of indicating the data payload size - either explicitly or by creating a system of metadata headers - to indicate how much data should be read, and exiting after that much data has been read or the operation has timed out

这两个是我能想到的最好的,并且似乎得到了其他基于 TCP 的协议(如 HTTP)和其他任何 RPC 协议的验证.

These two are the best I could come up with and seem to be validated by the likes of other TCP-based protocols like HTTP and generally any other RPC out there.

希望这可以为某人节省一些时间.

Hopefully this saves someone some time.

这篇关于C# NetworkStream.DataAvailable 似乎不可靠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆