我在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的套接字处理的一个简单示例是在其中一个示例项目中(事实上,这里)
最终是的:你在谈论序列化.这可以采用多种形式,尤其是在.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的套接字处理的一个简单示例是在其中一个示例项目中(事实上,这里)
如果您不需要丰富的序列化 - 如果您只想将结构写入字节数组,请考虑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等传输它,然后在另一端使用相同的类进行反序列化.
序列化是最简单的方法,因为系统直接支持它.但是,对于大而复杂的对象存在一些性能问题.在你的情况下,听起来像序列化是要走的路.如果您想要更低级别的东西,您可以查看BinaryWriter/BinaryReader,它允许您自己完成工作.