C#NetworkStream.DataAvailable似乎不可靠

本文关键字:不可靠 DataAvailable C#NetworkStream | 更新日期: 2024-10-18 21:12:31

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

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

实施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,即

实施3(有效,但次优)

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();
}

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

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

C#NetworkStream.DataAvailable似乎不可靠

看起来。DataAvailable确实是可靠的,而且由于数据通过网络到达的速度可能比从流中读取数据的速度慢,DataAvailable可以在我的应用程序认为是消息的开始和结束之间切换。

我回答并结束这个问题,因为我相信唯一的解决方案是:

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

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

这两个是我能想到的最好的,似乎已经被其他基于TCP的协议验证了,比如HTTP和其他任何RPC。

希望这能为某人节省一些时间。