我正在通过C#通过TCPListener和TCPClient提供的TCP接口发送自己的结构“数据包”对象。
这是我的结构
[Serializable] struct RemuseNetworkPacket { public String ApplicationCode; public String ReceiverCode; public RemusePacketType Type; public uint ID; public uint cID; public String Name; public byte[] Data; public String Text; public System.Drawing.Point Coords; public String Timestamp; public String Time; public String SenderName; public byte[] Serialize() { var buffer = new byte[Marshal.SizeOf(typeof(RemuseNetworkPacket))]; var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned); var pBuffer = gch.AddrOfPinnedObject(); Marshal.StructureToPtr(this, pBuffer, false); gch.Free(); return buffer; } public void Deserialize(byte[] data) { var gch = GCHandle.Alloc(data, GCHandleType.Pinned); this = (RemuseNetworkPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(RemuseNetworkPacket)); gch.Free(); } }
我在结构中使用序列化方法来准备和检索发送前后的数据。
为了让接收者知道传入数据的大小,我将一些标头数据添加到要发送的字节中,格式为 l = 212; … ,这意味着length = 212; 而 … 是包的其余部分。
在接收端,我一直在搜索,直到找到整个l = xxxx; 然后我创建一个没有头的新字节数组,然后尝试反序列化数据。用于反序列化的数据包字节是:tcp流的 缓冲区。长度-foundHeaderSize (l = xxxx;)
如果我在同一台计算机上运行客户端和服务器,则可以正常运行,但是如果我将客户端和服务器安装在不同的计算机上,则会出现异常,并且崩溃。
在对数据包进行反序列化时会发生异常,说明:
Stacktrace:System.Runtime.InteropServices.PtrToStructure(IntPtr ptr,类型structureType .. *
我正在寻求帮助以确定问题的原因。我不能通过网络上的对象这样做吗?
您应该实现适当的 length-prefixing ,而不是用字符串来表示您的数据包长度,然后减去该字符串的长度来知道从哪里开始读取。长度前缀与数据头结合使用将使您能够根据数据包的大小读取每个数据包,然后数据头将帮助您确定如何处理数据。
普通的长度前缀为您发送的每个“数据包”添加一个固定的报头。要创建此标头,您需要将整数(数据的长度)转换为字节,这将导致4个字节,然后在其后添加数据标头以及数据包的其余部分(即您要发送的数据) 。
这将创建以下数据包结构:
[Length (4 bytes)][Header (1 byte)][Data (x byte(s))]
读取数据包非常简单:
读取前4个字节(Length),将其转换并将其分配给整数变量。
Length
读取下一个字节(数据头)并将其放入变量中。
x将字节读取到字节数组(其中x是您在步骤1中声明的整数)。
x
使用步骤2中的数据标头确定如何处理数据(步骤3中的字节数组)。
在 我之前的答案 之一中,您可以看到我上面刚刚解释的示例。