C#通过TCP

时间:2016-05-20 08:13:02

标签: c# serialization tcp

我通过TCP接口发送我自己的struct“packet”对象,C#通过TCPListener和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();
    }
}

我在结构中使用序列化方法来准备和检索发送之前和之后的数据。

为了让接收方知道输入数据的大小,我将一些标题数据添加到正在发送的字节中,格式为 l = 212; ... ,这意味着长度= 212 ;并且 ... 是数据包的其余部分。

在接收端我搜索到这个,直到找到整个l = xxxx;然后我创建一个没有标题的新字节数组,然后尝试反序列化数据。 用于反序列化的数据包字节是:tcp stream的 buffer.Length - foundHeaderSize (l = xxxx;)

如果我在同一台机器上运行客户端和服务器,它可以正常运行,但是如果我在不同的机器上安装客户端和服务器,我会遇到异常并且崩溃。

当数据包被反序列化时发生异常,说:

* System.Runtime.InteropServices.SafeArrayTypeMismatchException 阵列的运行时类型与元数据中记录的sb类型之间出现不匹配 System.Runtime.InteropServices.PtrToStructureHelper

堆栈跟踪: System.Runtime.InteropServices.PtrToStructureHelper (IntPtr ptr,Object structure,Boolean allowValueClasses)at System.Runtime.InteropServices.PtrToStructure(IntPtr ptr,Type structureType .. *

我正在寻求帮助以确定问题的原因。 对于来自网络的对象,我不能这样做吗?

2 个答案:

答案 0 :(得分:3)

您应该实现正确的长度前缀,而不是使用字符串表示数据包长度,然后减去字符串的长度以了解从何处开始读取。长度前缀与数据头相结合将使您能够根据其大小读取每个数据包,然后数据头将帮助您确定如何处理数据。

普通长度前缀为您发送的每个“数据包”添加一个固定的标头。要创建此标头,您将整数(数据的长度)转换为字节,这将产生4个字节,然后在此之后添加数据标头以及数据包的其余部分(这是您要发送的数据)

这将创建以下数据包结构:

[Length (4 bytes)][Header (1 byte)][Data (x byte(s))]

读取数据包非常简单:

  1. 读取前4个字节(Length),转换并将它们分配给整数变量。

  2. 读取下一个字节(数据标题)并将其放入变量中。

  3. x字节读取到字节数组(其中x是您在步骤1中声明的整数)。

  4. 使用步骤2中的数据标头确定如何处理数据(步骤3中的字节数组)。

  5. my previous answers中的一个中,你可以看到我刚才解释过的一个例子。

答案 1 :(得分:0)

结构的序列化二进制数据可能因平台和操作系统而异。 例如不同的排列,不同的长度 这可能是您的代码在同一台机器上工作的原因,而不是在不同的机器上。

我建议您使用像Google ProtoBuf这样的库(快速) https://developers.google.com/protocol-buffers/docs/csharptutorial

或依赖于使用例如C#对象序列化XML序列化(慢) https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx