C#通过TCP接收后反序列化一个结构 [英] C# Deserializing a struct after receiving it through TCP

查看:13
本文介绍了C#通过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))]

读取数据包非常简单:

  1. 读取前 4 个字节(Length),将它们转换并赋值给一个整型变量.

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆