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

查看:78
本文介绍了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
之间发生了不匹配
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

Stacktrace:
System.Runtime .InteropServices.PtrToStructureHelper
(IntPtr ptr,对象结构,布尔值allowValueClasses),位于
System.Runtime.InteropServices.PtrToStructure(IntPtr ptr,类型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?

推荐答案

不是用字符串来表示数据包的长度,而是减去字符串的长度要知道从哪里开始阅读,您应该实施适当的 length-prefixing 。长度前缀与数据头结合使用将使您能够根据数据包的大小读取每个数据包,然后数据头将帮助您确定如何处理数据。

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个字节(长度),将其转换并分配给整数变量。

  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天全站免登陆