C# NetworkStream.DataAvailable 似乎不可靠

标签 c# sockets tcp networkstream

我有一个应用程序使用 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();
}

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

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

最佳答案

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

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

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

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

这两个是我能想到的最好的,并且似乎已被其他基于 TCP 的协议(protocol)(如 HTTP)和通常的任何其他 RPC 之类的协议(protocol)所验证。

希望这可以节省一些时间。

关于C# NetworkStream.DataAvailable 似乎不可靠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36731247/

相关文章:

重置 Wi-Fi 连接后,Android 套接字行为异常

python - 向服务器 pyzmq 发送数据时出现问题

go - 您可以使用 icmp 定位特定端口吗?

C# 400 错误请求和长字符 api 有多重要

c# - 端口号和 URL

c# - Asp.net Core 电子邮件确认有时会显示 InvalidToken

c# - 套接字在一定时间后受到限制

c# - 调用派生类的非继承方法

java - 通过带有对象输入/输出流的 Socket 发送的对象的大小真的很重要吗?

java - 在java TCP连接中绑定(bind)一个接口(interface)