当前位置:  开发笔记 > 编程语言 > 正文

C#通过socket发送结构对象

如何解决《C#通过socket发送结构对象》经验,为你挑选了3个好方法。

我在c#中用客户端/服务器编程做了一些阅读.我对这个过程非常熟悉,可以提出以下问题:

我如何通过tcp/ip而不仅仅是字符串传输结构对象?

我的应用程序是一个具有聊天功能的联网游戏.所以我不想只传输文本,而是想要构建一个包含两个字段的数据结构或类结构:i.包类型ii.数据包类型的数据

我会在应用程序执行期间需要时传输它,并在接收端解码数据对象并将其放在它所属的位置.

我不寻找代码,只是一些想法和搜索语句,我可以提供给谷歌,所以我会; 有一个更好的理解.

香港专业教育学院阅读有关序列化/反序列化,是他的方式去?

谢谢.


我已经检查了相关主题但仍然需要进一步指导的帖子.


Marc Gravell.. 7

最终是的:你在谈论序列化.这可以采用多种形式,尤其是在.NET中,但最终您需要选择:

文本与二进制; 直接二进制文件往往比文本小,因为它通常涉及较少的解析等; text(xml,json等)通常在流中表示为UTF8(尽管可以进行任何编码).它们具有广泛的人类可读性,尽管更加冗长,但通常可以很好地压缩.

合同与元数据; 基于合同的序列化器专注于表示数据 - 假设管道的另一端理解结构,但不假设它们共享一个实现.这具有局限性,因为您不能突然引入一些完全出乎意料的子类,而是使其与平台无关.相比之下,基于元数据的序列化程序在流上发送类型信息(即"这是一个My.Namespace.FooBar实例).这使得它很容易工作,但很少在不同平台之间工作(通常不在版本之间) - 并且所有类型信息可能很冗长

手动与自动; 事实上:手动序列化器在带宽方面通常是最有效的,因为您可以手动自定义流 - 但需要花费很多精力才能理解序列化批次.自动序列化器更适合一般用途(实际上:大多数场景).除非你别无选择,否则不要手动.自动序列化器可以处理担心不同类型数据等的所有复杂问题.

手册串行方法包括(只提的是"串行"关键字): ,TextWriter,XmlWriter,IXmlSerializable,.BinaryWriter ISerializable你不想这样做......

更多关注自动序列化器:

               | Contract               | Metadata
===============+========================+===========================
  Text         | XmlSerializer          | SoapFormatter
               | DataContractSerializer | NetDataContractSerializer
               | Json.NET               |
---------------+------------------------+---------------------------
  Binary       | protobuf-net           | BinaryFormatter

既然你在谈论原始流,我的偏好是基于二进制契约的序列化器 - 但是,我写了protobuf-net,所以我可能有偏见;-p

与常见的RPC堆栈进行比较:

"远程"使用 BinaryFormatter

"asmx"web服务(包括WSE*)使用 XmlSerializer

WCF可以使用很多,最常见的,DataContractSerializer或者NetDataContractSerializer有时XmlSerializer(它也可以配置为使用例如protobuf-net)

我可以愉快地编写一个在流上使用protobuf-net来表示不同类型的不同消息的示例,但是使用protobuf-net的套接字处理的一个简单示例是在其中一个示例项目中(事实上,这里)



1> Marc Gravell..:

最终是的:你在谈论序列化.这可以采用多种形式,尤其是在.NET中,但最终您需要选择:

文本与二进制; 直接二进制文件往往比文本小,因为它通常涉及较少的解析等; text(xml,json等)通常在流中表示为UTF8(尽管可以进行任何编码).它们具有广泛的人类可读性,尽管更加冗长,但通常可以很好地压缩.

合同与元数据; 基于合同的序列化器专注于表示数据 - 假设管道的另一端理解结构,但不假设它们共享一个实现.这具有局限性,因为您不能突然引入一些完全出乎意料的子类,而是使其与平台无关.相比之下,基于元数据的序列化程序在流上发送类型信息(即"这是一个My.Namespace.FooBar实例).这使得它很容易工作,但很少在不同平台之间工作(通常不在版本之间) - 并且所有类型信息可能很冗长

手动与自动; 事实上:手动序列化器在带宽方面通常是最有效的,因为您可以手动自定义流 - 但需要花费很多精力才能理解序列化批次.自动序列化器更适合一般用途(实际上:大多数场景).除非你别无选择,否则不要手动.自动序列化器可以处理担心不同类型数据等的所有复杂问题.

手册串行方法包括(只提的是"串行"关键字): ,TextWriter,XmlWriter,IXmlSerializable,.BinaryWriter ISerializable你不想这样做......

更多关注自动序列化器:

               | Contract               | Metadata
===============+========================+===========================
  Text         | XmlSerializer          | SoapFormatter
               | DataContractSerializer | NetDataContractSerializer
               | Json.NET               |
---------------+------------------------+---------------------------
  Binary       | protobuf-net           | BinaryFormatter

既然你在谈论原始流,我的偏好是基于二进制契约的序列化器 - 但是,我写了protobuf-net,所以我可能有偏见;-p

与常见的RPC堆栈进行比较:

"远程"使用 BinaryFormatter

"asmx"web服务(包括WSE*)使用 XmlSerializer

WCF可以使用很多,最常见的,DataContractSerializer或者NetDataContractSerializer有时XmlSerializer(它也可以配置为使用例如protobuf-net)

我可以愉快地编写一个在流上使用protobuf-net来表示不同类型的不同消息的示例,但是使用protobuf-net的套接字处理的一个简单示例是在其中一个示例项目中(事实上,这里)



2> Cheeso..:

如果您不需要丰富的序列化 - 如果您只想将结构写入字节数组,请考虑Marshal类.

例如,考虑C#中的tar应用程序.tar格式基于512字节块,并且系列中的第一个块具有规则结构.理想情况下,应用程序要公正blitt从磁盘文件中的数据,右转入结构.该Marshal.PtrToStructure方法做到这一点.这是结构.

    [StructLayout(LayoutKind.Sequential, Size=512)]
    internal struct HeaderBlock
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        public byte[]   name;    // name of file. 

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   mode;    // file mode

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   uid;     // owner user ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   gid;     // owner group ID

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   size;    // length of file in bytes

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        public byte[]   mtime;   // modify time of file

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[]   chksum;  // checksum for header

        // ... more like that... up to 512 bytes. 

然后这是一个执行blitting的泛型类.

internal class RawSerializer
{
    public T RawDeserialize( byte[] rawData )
    {
        return RawDeserialize( rawData , 0 );
    }    

    public T RawDeserialize( byte[] rawData , int position )
    {
        int rawsize = Marshal.SizeOf( typeof(T) );
        if( rawsize > rawData.Length )
            return default(T);

        IntPtr buffer = Marshal.AllocHGlobal( rawsize );
        Marshal.Copy( rawData, position, buffer, rawsize );
        T obj = (T) Marshal.PtrToStructure( buffer, typeof(T) );
        Marshal.FreeHGlobal( buffer );
        return obj;
    }

    public byte[] RawSerialize( T item )
    {
        int rawSize = Marshal.SizeOf( typeof(T) );
        IntPtr buffer = Marshal.AllocHGlobal( rawSize );
        Marshal.StructureToPtr( item, buffer, false );
        byte[] rawData = new byte[ rawSize ];
        Marshal.Copy( buffer, rawData, 0, rawSize );
        Marshal.FreeHGlobal( buffer );
        return rawData;
    }
}

您可以将该类与任何结构一起使用.您必须使用LayoutKind.Sequential并将自己限制为blittable类型(基本上是基元和相同的数组)才能使用此方法.它在代码,性能和内存方面快速而有效,但它在如何使用方面受到一定限制.

获得字节数组后,可以通过NetworkStream等传输它,然后在另一端使用相同的类进行反序列化.



3> James Keesey..:

序列化是最简单的方法,因为系统直接支持它.但是,对于大而复杂的对象存在一些性能问题.在你的情况下,听起来像序列化是要走的路.如果您想要更低级别的东西,您可以查看BinaryWriter/BinaryReader,它允许您自己完成工作.


也许你想详细说明二进制和其他序列化之间的区别来解释为什么二进制文件会更有效.
最终,所有序列化都是"二进制" - 区别在于如何.
推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有