我有一个使用TCP套接字来交换字节数组的应用程序,在大多数情况下包含JSON字符串数据。我所经历的是,对于较大的消息和不太理想的网络条件,使用NetworkStream.DataAvailable似乎不是检测消息结束的可靠方法。似乎在某些情况下,即使只有部分消息已由对等方传输(使用TcpClient.GetStream().Write(data, 0, data.Length
),DataAvailable也会设置为false。这导致不完整的数据被传递回应用程序,在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();
}
似乎一个解决方案非常有效但完全不是最佳的是在NetworkStream.DataAvailable为false(在循环内部)的情况下添加Thread.Sleep以允许传递数据。然而,这严重限制了我想避免的整体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();
}
我真的很想找到一种方法来保持循环,直到所有数据都传递完毕。正如我所提到的,我在客户端上从零到数据长度进行简单的写操作,所以我不认为那里存在问题。
之前有没有人有这样的经历和推荐?
答案 0 :(得分:1)
似乎.DataAvailable确实是可靠的,因为数据通过网络到达的速度可能比从流中读取数据的速度慢,所以.DataAvailable可以在我的应用程序认为的开始和结束之间翻转一条消息。
我回答并关闭这个,因为我相信唯一的解决方案是:
1)添加一个超额接收超时值,并在读取循环中执行thread.sleep,并在达到接收超时后使操作到期
2)实现一些指示数据有效负载大小的机制 - 显式或通过创建元数据头系统 - 来指示应该读取多少数据,并在读取了大量数据或操作超时后退出
这两个是我能想到的最好的,似乎可以通过其他基于TCP的协议(如HTTP)和其他任何其他RPC来验证。
希望这可以节省一些时间。