很久以前我找到了有关为客户端/服务器目的创建和管理消息结构类的有用指南,但我再也找不到了。
必须包含4个字段:
_FLAG (integer from 0 to 1000)
_FROM (string up to 16 chars)
_TO (same as above)
_DATA (string up to 48 chars)
我希望能够轻松地将其转换为字节数组,通过套接字发送,然后接收,将其转换为struct和read。最好的方法是什么?
修改
感谢您的回答(也许我不够清楚),但这不是我想要的。我刚刚发现了一些有用的东西并且这样做了:
[MarshalAs(UnmanagedType.U4)]
public uint _flag;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String _from;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public String _to;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public String _data;
public byte[] Serialize()
{
var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];
var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var pBuffer = gch.AddrOfPinnedObject();
Marshal.StructureToPtr(this, pBuffer, false);
gch.Free();
return buffer;
}
public void Deserialize(ref byte[] data)
{
var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));
gch.Free();
}
答案 0 :(得分:0)
如果您使用现有的序列化程序类之一,它们会带来一些费用。您可以创建自己的序列化程序,仅满足您的需求。在使用标准和自己的实现之间总是存在权衡。这是我为我的一个项目创建的示例。用户CreateFromBytes
和StoreToBytes
从字节数组中获取或恢复。如果你使用流(也可能在你的情况下工作),流版本是好的,它有助于避免额外的转换。
// well, there's a bad naming for this class as T can be of any type.
public abstract class ClassSerializer<T> : IClassSerializer<T>
{
public const int VersionNull = 0;
public abstract int StoreToStream(Stream stream, T item);
public abstract T CreateFromStream(Stream stream);
public virtual byte[] StoreToBytes(T item)
{
byte[] result;
using (var stream = new MemoryStream(16))
{
StoreToStream(stream, item);
result = stream.ToArray();
}
return result;
}
public virtual T CreateFromBytes(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
{
return CreateFromStream(stream);
}
}
public int WriteVersionNull(Stream stream)
{
return stream.WriteIntVariableLength(VersionNull);
}
}
对于特定的类(在你的情况下结构;我建议你使用类;你没有从结构中获得很多好处;无论如何它转换为字节数组)你应该创建一个像这样的特定序列化器。 / p>
public class DescriptionSerializer : ClassSerializer<Description>
{
private const byte Version = 1;
public override int StoreToStream(Stream stream, KeyDescription item)
{
if (item == null)
{
return WriteVersionNull(stream);
}
var count = stream.WriteIntVariableLength(Version);
count += stream.WriteString(item.StringProperty);
count += stream.WriteBytes(item.BytesPropery);
count += stream.WriteIntVariableLength(item.IntegerProperty);
return count;
}
public override Description CreateFromStream(Stream stream)
{
var version = stream.ReadIntVariableLength();
if (version == VersionNull) return null;
if (version != Version)
{
throw new InvalidDataException(
string.Format("The stream version '{0}' is incorrect. The data cannot be deserialized. ", version));
}
var stringProperty = stream.ReadString();
var bytesProperty = stream.ReadBytes();
var integerProperty = stream.ReadIntVariableLength();
return new Description(
stringProperty,
bytesProperty,
integerProperty);
}
}
你需要一个可以为流编写不同基本类型的辅助类。
public static class SerializationHelper
{
public static int WriteArray<T>(
[NotNull] this Stream stream,
[NotNull] IClassSerializer<T> serializer,
[CanBeNull] T[] items ) where T: class
{
if (items == null)
{
return stream.WriteIntVariableLength(0);
}
var count = stream.WriteIntVariableLength(items.Length);
foreach (var item in items)
{
count += serializer.StoreToStream(stream, item);
}
return count;
}
public static T[] ReadArray<T>(
[NotNull] this Stream stream,
[NotNull] IClassSerializer<T> serializer) where T : class
{
var length = stream.ReadIntVariableLength();
if (length <= 0)
{
return new T[0];
}
var result = new T[length];
for (int i = 0; i < length; i++)
{
var item = serializer.CreateFromStream(stream);
result[i] = item;
}
return result;
}
public static int WriteString([NotNull] this Stream stream, [CanBeNull] string item)
{
if (item == null)
{
return stream.WriteIntVariableLength(0);
}
var buf = Encoding.UTF8.GetBytes(item);
var count = stream.WriteIntVariableLength(buf.Length);
stream.Write(buf, 0, buf.Length);
return count + buf.Length;
}
public static string ReadString([NotNull] this Stream stream)
{
var len = stream.ReadIntVariableLength();
if (len <= 0) return null;
var buf = new byte[len];
var count = stream.Read(buf, 0, len);
if (count != buf.Length)
{
throw new InvalidDataException("There should be more bytes to read.");
}
var result = Encoding.UTF8.GetString(buf);
return result;
}
public static int WriteIntVariableLength([NotNull] this Stream stream, Int32 value)
{
var len = unchecked((UInt32)value);
if (len < 0x80)
{
stream.Write(new [] { (byte) (len & 0x7F) }, 0, 1);
return 1;
}
if (len < 0x4000)
{
stream.Write(new[] { (byte)((len & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len>>7) & 0x7F)) }, 0, 1);
return 2;
}
if (len < 0x200000)
{
stream.Write(new[] { (byte)((len & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 7) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)((len >> 14) & 0x7F) }, 0, 1);
return 3;
}
if (len < 0x10000000)
{
stream.Write(new[] { (byte)((len & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 7) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 14) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 21) & 0x7F)) }, 0, 1);
return 4;
}
stream.Write(new[] { (byte)((len & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 7) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 14) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 21) & 0x7F) | 0x80) }, 0, 1);
stream.Write(new[] { (byte)(((len >> 28) & 0x0F)) }, 0, 1);
return 5;
}
public static Int32 ReadIntVariableLength([NotNull] this Stream stream)
{
//var buf = new byte[sizeof(Int32)];
var b1 = stream.ReadByte();
if (b1==-1) throw new InvalidDataException("Unexpected end of the stream");
if ((b1 & 0x80) == 0)
{
return b1;
}
var b2 = stream.ReadByte();
if (b2==-1) throw new InvalidDataException("Unexpected end of the stream");
if ((b2 & 0x80) == 0)
{
return (b1 & 0x7F) + ((b2 & 0x7F) <<7);
}
var b3 = stream.ReadByte();
if (b3==-1) throw new InvalidDataException("Unexpected end of the stream");
if ((b3 & 0x80) == 0)
{
return (b1 & 0x7F) + ((b2 & 0x7F) <<7) + ((b3 & 0x7F) <<14);
}
var b4 = stream.ReadByte();
if (b4==-1) throw new InvalidDataException("Unexpected end of the stream");
if ((b4 & 0x80) == 0)
{
return (b1 & 0x7F) + ((b2 & 0x7F) <<7) + ((b3 & 0x7F) <<14) + ((b4 & 0x7F) <<21);
}
var b5 = stream.ReadByte();
if (b5 == -1) throw new InvalidDataException("Unexpected end of the stream");
return (b1 & 0x7F) + ((b2 & 0x7F) << 7) + ((b3 & 0x7F) << 14) + ((b4 & 0x7F) << 21) + ((b5 & 0x0F) << 28);
}
public static int WriteBytes([NotNull] this Stream stream, [CanBeNull]byte[] bytes)
{
if (bytes == null)
{
return stream.WriteIntVariableLength(0);
}
var length = bytes.Length;
var count = stream.WriteIntVariableLength(length);
stream.Write(bytes, 0, length);
return count + length;
}
public static byte[] ReadBytes([NotNull] this Stream stream)
{
var length = stream.ReadIntVariableLength();
if (length == 0) return new byte[0];
var bytes = new byte[length];
var count = stream.Read(bytes, 0, length);
if (count != length)
{
throw new InvalidDataException("There should be more bytes");
}
return bytes;
}
}
您可以在StoreToStream
和CreateFromStream
方法中使用序列化程序类来序列化其他类型,如下所示:
public override int StoreToStream(Stream stream, SomeClass item)
{
if (item == null)
{
return WriteVersionNull(stream);
}
var count = stream.WriteIntVariableLength(Version);
count += new SubType1Serializer().StoreToStream(stream, item.SubType1);
count += new SubType2Serializer().StoreToStream(stream, item.SubType2);
我希望这个想法很清楚,但我没有提供详细的说明。