2016-04-07 116 views
0

我通过网络发送数据。要通过网络发送这些数据,我将它打包成一个字节数组。结构对齐建议?

现在数据类型由一个字节和3个浮点组成,总共13个字节。要阅读这个,我需要知道结构的大小。使用Marshal的sizeOf不会返回序列化字节数组的“正确”大小。

现在我知道发生了什么。元帅正在返回我的结构管理对齐的大小。我也知道如果我标记它

[StructLayout(LayoutKind.Sequential, 
Pack = 1)] 

然后它会返回“正确”的大小。我的问题是最好的方法是什么?我知道它在填充位中增加的原因是因为处理器喜欢所有要对齐的东西(如果我没有弄错,请随时纠正我!)

性能损失是否值得这样做,以便我可以使用sizeof以反序列化数组,或者最好是使用我自己从数组中读取的常量来读取数组,或者通过填充它来减少数组中的几个字节的大小惩罚(我最不喜欢的选项)。

如果有什么我误解为什么元帅希望以哪种方法是b EST对准内存或其他任何东西,请不吝赐教我,给我建议。

回答

2

我通过网络发送数据。要通过网络发送这些数据,我将它打包成一个字节数组。

不要这样做。

MarshalStructLayout适用于本地互操作,不适用于网络IO和分散。

为IO序列化对象实例的正确方法是手动编写它,这样您可以精确控制序列化表示形式,并且可以保证正确的格式(正确的是多字节值的字节序)。使用BinaryWriter(或更好,Jon Skeet的MiscUtil. EndianBinaryReaderhttp://jonskeet.uk/csharp/miscutil/)。

struct Foo { 
    public const Int32 Size = sizeof(Byte) + (sizeof(Single) * 3); 
    public Byte B; 
    public Single F1; 
    public Single F2; 
    public Single F3; 

    public void Serialize(EndianBinaryWriter wtr) { 
     wtr.Write(Size); 
     wtr.Write(B); 
     wtr.Write(F1); 
     wtr.Write(F2); 
     wtr.Write(F3); 
    } 

    public static Foo Deserialize(EndianBinaryReader rdr) { 
     if(rdr.ReadInt32() != Size) throw new ... 
     Foo f; 
     f.B = rdr.ReadByte(); 
     f.F1 = rdr.ReadSingle(); 
     f.F2 = rdr.ReadSingle(); 
     f.F3 = rdr.ReadSingle(); 
     return f; 
    } 
} 

把这想成是一种ISerializable -lite。您可以在网络程序中使用它,方法是使对象与您的开放式网络套接字连接对应,然后将其包装在对象周围,并通过这些对象执行所有IO操作。作为奖励,您可以免费获得磁盘序列号:只需使用FileStream而不是网络流。

+0

您描述的方法实际上是我打包数据的方式。我的问题涉及到更多,当我打包结构时,它是13字节,正如我所料,但是当我读它时,如果我尝试通过使用结构的大小来读取它(即Marshal.sizeOf(typeof(Type ))它返回16个字节,因为(从我所假设的)将字节对齐到16个字节的效率。我只是问我是否应该只使用我知道类型的大小读取数组,然后每次更改大小 –

+0

@Damamaoto在序列化中,最好为每个自描述的对象编写一个头文件:它应该包含某种魔术字符串(用于标识对象类型),一个版本号和序列化对象的长度(以字节为单位),然后从流中读回并用作读取对象的基础。 – Dai

+0

@DYamamoto我用一个检查和写入大小信息的示例修改了我的代码。 – Dai