【问题标题】:Structs to Byte Arrays to send over sockets结构到字节数组以通过套接字发送
【发布时间】:2009-03-16 15:06:27
【问题描述】:

从结构中获取字节数组以通过 TCP 套接字发送的最佳方法是什么?我正在使用 .Net(VB 或 C#)。

【问题讨论】:

  • 您的环境是什么(.NET、Java、C/C++)?没有这些信息,什么都做不了。
  • 你使用什么编程语言?

标签: .net sockets serialization bytearray struct


【解决方案1】:

一种选择是将结构的本机表示直接编组到缓冲区中,类似于memcpy 在 C 中的工作方式。

您需要在结构中添加适当的属性,

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

然后您可以使用以下方法对其进行序列化:

    /// <summary>
    /// Serializes the specified object into a byte array.
    /// </summary>
    /// <param name="nativeObject">The object to serialize.</param>
    /// <returns></returns>
    public static byte[] Serialize(object obj)
    {
        Type objectType = obj.GetType();
        int objectSize = Marshal.SizeOf(obj);
        IntPtr buffer = Marshal.AllocHGlobal(objectSize);
        Marshal.StructureToPtr(obj, buffer, false);
        byte[] array = new byte[objectSize];
        Marshal.Copy(buffer, array , 0, objectSize);
        Marshal.FreeHGlobal(buffer);
        return array;
    }

不过,这是迄今为止最不便携的解决方案。双方都需要使用相同的对齐方式和字节顺序,如果您需要更改结构本身,则需要自己实现版本控制。

在大多数情况下,您的序列化格式不应该是内部数据结构的直接副本。

【讨论】:

    【解决方案2】:

    您应该查看Serialization。您可以使用多种选项,从 Protocol Buffers(由排名第一和第二的 SO 用户实施)到 XmlBinaryFormatter

    【讨论】:

      【解决方案3】:

      为什么不直接使用二进制读取器来填充结构的字段,然后再次读取它们?您只需要知道结构中字段的大小及其在流中的位置,无需非托管解决方案。 这是我写的waveplayer的一个例子..

          /// <summary>Copies header to a stream</summary>
          /// <param name="waveData">Wav data stream</param>
          /// <param name="format">WAVEFORMATEX wav format</param>
          /// <returns>Stream</returns>
          public Stream CreateStream(Stream waveData, WAVEFORMATEX format)
          {
              MemoryStream stream = new MemoryStream();
              BinaryWriter writer = new BinaryWriter(stream);
      
              writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF".ToCharArray()));
              writer.Write((Int32)(waveData.Length + 36)); //File length minus first 8 bytes of RIFF description
              writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt ".ToCharArray()));
              writer.Write((Int32)16); //length of following chunk: 16
              writer.Write((Int16)format.wFormatTag);
              writer.Write((Int16)format.nChannels);
              writer.Write((Int32)format.nSamplesPerSec);
              writer.Write((Int32)format.nAvgBytesPerSec);
              writer.Write((Int16)format.nBlockAlign);
              writer.Write((Int16)format.wBitsPerSample);
              writer.Write(System.Text.Encoding.ASCII.GetBytes("data".ToCharArray()));
              writer.Write((Int32)waveData.Length);
      
              waveData.Seek(0, SeekOrigin.Begin);
              byte[] b = new byte[waveData.Length];
              waveData.Read(b, 0, (int)waveData.Length);
              writer.Write(b);
              writer.Seek(0, SeekOrigin.Begin);
              return stream;
          }
      

      【讨论】:

        【解决方案4】:

        如果您愿意处理字节序(在异构网络中进行通信),那么做到这一点的唯一方法是逐个字段。

        【讨论】:

          【解决方案5】:

          您需要更具体一些并告诉我们您的语言。

          对于许多语言来说,有现成的框架,甚至是语言标准环境的一部分,可以做这些事情。

          【讨论】:

            【解决方案6】:

            我假设是 C 语言,因为你说“结构”

            你可以使用一个名为

            的函数

            ssize_t write(int fd, const void *buf, size_t 计数);

            其中 FD 是套接字的文件描述符 buffer 是结构体的地址,count 是字节数

            您可以将其用作:

            写(socket,&struct_var, sizeof(struct_var));

            【讨论】:

            • 这是否考虑了对齐、打包和字节序?
            • 不,它没有。对于字节序,您必须使用像 htonl、htons、ntohl、ntohs 这样的函数,它们在主机和网络字节顺序之间转换值。对于打包,您可以使用您的编译器来强制执行某种打包结构或对齐方式。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-22
            • 2016-06-06
            • 1970-01-01
            • 2016-01-11
            • 1970-01-01
            相关资源
            最近更新 更多