【发布时间】:2017-06-15 07:07:29
【问题描述】:
您好,我正在尝试在客户端/服务器应用程序之间发送和接收一些数据。
类
[Serializable]
public class ScanSessie
{
public string UserId { get; set; }
public int TotalScanned { get; set; }
public string Status { get; set; }
public string DeviceId { get; set; }
}
Serializer 和 Deserializer 扩展方法:
public static class SerializerDeserializerExtensions
{
public static byte[] Serializer(this object _object)
{
byte[] bytes;
using (var _MemoryStream = new MemoryStream())
{
IFormatter _BinaryFormatter = new BinaryFormatter();
_BinaryFormatter.Serialize(_MemoryStream, _object);
bytes = _MemoryStream.ToArray();
}
return bytes;
}
public static T Deserializer<T>(this byte[] _byteArray)
{
T ReturnValue;
using (var _MemoryStream = new MemoryStream(_byteArray))
{
IFormatter _BinaryFormatter = new BinaryFormatter();
ReturnValue = (T)_BinaryFormatter.Deserialize(_MemoryStream);
}
return ReturnValue;
}
}
我尝试发送和反序列化的示例数据是:
List<ScanSessie> scannerCl = new List<ScanSessie>();
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
scannerCl.Add(new ScanSessie { DeviceId = "0x00456321", UserId = "123456", Status = "scannen ...", TotalScanned = 0 });
使用以下代码发送:
NetworkStream broadcastStream = statusSocket.GetStream();
Byte[] broadcastBytes = SerializerDeserializerExtensions.Serializer(scannerCl);
broadcastStream.Write(broadcastBytes, 0, broadcastBytes.Length);
broadcastStream.Flush();
接收流代码。忽略 n.DataAvailable 循环。出于测试目的,我在缓冲区下方发送非常小的数据包,这些数据包在一个部分中传输。
using (TcpClient client = new TcpClient())
{
await client.ConnectAsync("10.184.32.39", 8888);
ConnectionEstabilished?.Invoke();
byte[] message = new byte[1024 * 8];
int bytesRead;
using (NetworkStream n = client.GetStream())
{
while (true)
{
bytesRead = 0;
try
{
if(n.CanRead)
{
do
{
bytesRead = await n.ReadAsync(message, 0, message.Length);
}
while (n.DataAvailable);
}
//bytesRead = await n.ReadAsync(message, 0, 4096);
//bytesRead = await n.ReadAsync(message, 0, message.Length);
}
catch (Exception ex)
{
// some error hapens here catch it
Debug.WriteLine("DashboardClientConnect " + ex.Message + "\n" + ex.InnerException);
break;
}
}
接收代码将触发一个事件,其数据为 byte[] 定义为消息。 在我的处理事件中,我尝试使用以下方法对其进行反序列化:
private void Sc_NewDataReceived(byte[] scanner)
{
try
{
var result = scanner.Deserializer<List<ScanSessie>>();
}
catch(Exception ex)
{
Debug.WriteLine(ex.InnerException);
}
}
在反序列化步骤中,它会抛出异常(抛出异常:mscorlib.dll 中的“System.Runtime.Serialization.SerializationException”) 内部异常为空。
当我使用扩展方法而不通过网络发送一些示例数据时,反序列化工作完美无缺。
我也尝试过使用接收缓冲区大小。这似乎也没有帮助。示例数据大小在 1024*8 以下。
以发送数据长度为 600 字节为例。接收端缓冲区是否也需要相同大小?通常这应该是个问题,因为它是分块读取的。
两天后我放弃了。任何帮助,将不胜感激。我试图通过放置功能代码 sn-ps 来使问题提供信息。
【问题讨论】:
-
如果您的消息大小小于缓冲区大小 (1024*8) - 缓冲区的其余部分用零填充,这当然会阻止正确的反序列化。更不用说每次读取都会覆盖缓冲区的一部分(在
while DataAvailable循环中)。 -
不支持尝试使用 NetworkStream.Length,因此您需要定义一个固定的缓冲区大小。大或小。为了测试它,我检查了我的样本数据的大小,它是 606 字节。我也将接收缓冲区调整为 606 字节,同样的异常发生了。 while 循环确实覆盖了它。这是一个示例代码。发送数据远低于缓冲区大小,因此它不会循环它:)
-
您可以直接将
NetworkStream提供给BinaryFormatter,而不是通过MemoryStream进行序列化。但是,如果您确实想手动处理数据,请记住Read操作返回实际读取的字节数,并且它可能会以小于发送数据的块接收数据。收到0字节表示对方已经关闭了发送通道。 -
@C.Evenhuis 我了解缓冲区和块问题。在此示例中,情况并非如此。示例数据为 606 字节。它在一块没有块的情况下转移。如果数据比它可能发生的大。
-
@Shift 在较早的评论中,您说 while 循环正在覆盖您的数据,我很确定您没有接收一个块中的数据,因为循环如果没有要从流中读取的数据,则不会覆盖任何数据。
标签: c# networkstream