C#通过TCP接收后反序列化一个结构 [英] C# Deserializing a struct after receiving it through TCP
问题描述
我通过 C# 为 TCPListener 和 TCPClient 提供的 TCP 接口发送我自己的结构数据包"对象.
I am sending my own struct "packet" object through the TCP interface that C# offers with TCPListener and TCPClient.
这是我的结构
[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();
}
}
我正在使用结构中的序列化方法来准备和检索发送前后的数据.
I am using the serialization methods within the struct to prepare and retrieve the data before and after sending.
为了让接收者知道传入数据的大小,我在发送的字节中添加了一些头数据,格式为l=212;...,即长度=212;... 是数据包的其余部分.
In order to to let the receiver know the incoming data's size, I add some header data to the bytes being sent, in the format of l=212;... which means length = 212; and the ... is the rest of the packet.
在接收端我搜索这个直到我找到整个l=xxxx;然后我创建一个没有标头的新字节数组,然后尝试反序列化数据.用于反序列化的数据包字节是:tcp 流的 buffer.Length - foundHeaderSize (l=xxxx;)
On the receiving end I search for this until I find the entire l=xxxx; then I make a new byte array without the header, then attempt to deserialize the data. The packet byte to use for deserialization is: tcp stream's buffer.Length - foundHeaderSize (l=xxxx;)
如果我在同一台机器上运行客户端和服务器,它可以正常工作,但如果我在不同的机器上运行客户端和服务器,我会遇到异常并崩溃.
If I run the client and server on the same machine, it works without errors, however if I have the client and server on separate machines, I get exceptions and it crashes.
当数据包被反序列化时发生异常,说:
The exception takes place when the packet is being deserialized, saying:
*System.Runtime.InteropServices.SafeArrayTypeMismatchException数组的运行时类型与元数据中记录的 sb 类型之间发生不匹配System.Runtime.InteropServices.PtrToStructureHelper
*System.Runtime.InteropServices.SafeArrayTypeMismatchException Mismatch has occurred between the runtime type of the array and the sb type recorded in the metadata at System.Runtime.InteropServices.PtrToStructureHelper
堆栈跟踪:System.Runtime.InteropServices.PtrToStructureHelper(IntPtr ptr, Object 结构, Boolean allowValueClasses) atSystem.Runtime.InteropServices.PtrToStructure(IntPtr ptr, Type structureType..*
Stacktrace: System.Runtime.InteropServices.PtrToStructureHelper (IntPtr ptr, Object structure, Boolean allowValueClasses) at System.Runtime.InteropServices.PtrToStructure(IntPtr ptr, Type structureType..*
我正在寻求帮助以确定问题的原因.我不能对通过网络传来的对象这样做吗?
I'm asking for help to identify the cause of the problem. Can I not do it like this with objects that came over the network?
推荐答案
与其让一个字符串代表你的数据包长度,然后减去字符串的长度来知道从哪里开始读取,你应该实现正确的长度前缀.长度前缀结合数据头将使您能够根据其大小读取每个数据包,然后数据头将帮助您确定如何处理数据.
Instead of having a string represent your packet length and then subtract by the string's length to know where to start reading, you should implement proper length-prefixing. Length-prefixing combined with a data header will make you able to read every packet according to its size, then the data header will help you determine what to do with the data.
普通长度前缀为您发送的每个数据包"添加一个固定的标头.要创建此标头,您将整数(数据的长度)转换为字节,这将产生 4 个字节,然后在此之后添加数据标头以及数据包的其余部分(这是您要发送的数据).
Ordinary length-prefixing adds a fixed header to every "packet" you send. To create this header you convert an integer (the length of your data) to bytes, which will result in 4 bytes, then you add the data header after that and also the rest of the packet (which is the data you want to send).
这将创建以下数据包结构:
This will create the following packet structure:
[Length (4 bytes)][Header (1 byte)][Data (x byte(s))]
读取数据包非常简单:
读取前 4 个字节(
Length
),将它们转换并赋值给一个整型变量.
Read the first 4 bytes (
Length
), convert and assign them to an integer variable.
读取下一个字节(数据头)并将其放入一个变量中.
Read the next byte (the data header) and put that in a variable.
将 x
个字节读取到一个字节数组(其中 x
是您在步骤 1 中声明的整数).
Read x
bytes to a byte array (where x
is the integer you declared in step 1).
使用第 2 步中的数据标头来确定如何处理您的数据(第 3 步中的字节数组).
Use the data header from step 2 to determine what to do with your data (the byte array from step 3).
在 我之前的回答 之一中,您可以看到我刚刚解释的示例
In one of my previous answers you can see an example of what I just explained above.
这篇关于C#通过TCP接收后反序列化一个结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!