構造体からバイト配列を取得してTCPソケットを介して送信するための最良の方法は何ですか?.Net(VBまたはC#)を使用しています。
6 に答える
memcpy
1 つのオプションは、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;
}
それでも、これは移植性の最も低いソリューションです。両側で同じ配置とエンディアンを使用する必要があり、構造体自体を変更する必要がある場合は、バージョン管理を自分で実装する必要があります。
ほとんどの場合、シリアル化形式は内部データ構造の直接コピーであってはなりません。
Serializationを調べる必要があります。Protocol Buffers (1 位と 2 位の SO ユーザーによる実装) からXml、BinaryFormatterまで、多数のオプションを利用できます。
バイナリ リーダーを使用して構造体のフィールドにデータを入力し、それらを再度読み込んでみませんか? 知っておく必要があるのは、構造体のフィールドのサイズとストリーム内の位置だけです。アンマネージド ソリューションは必要ありません。これは、私が書いた 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;
}
エンディアンの面倒を見る(異種ネットワークで通信する)場合、これを行う唯一の方法はフィールドごとです。
より具体的に、言語を教えてください。
多くの言語には、これらの種類のことを行うための既製のフレームワーク、または言語の標準環境の一部があります。
あなたが「構造体」と言うので、私はC言語を想定しています
と呼ばれる関数を使用できます
ssize_t write(int fd、const void * buf、size_t count);
ここで、FDはソケットのファイル記述子であり、バッファは構造体のアドレスであり、countはバイト単位のサイズです。
あなたはそれを次のように使うでしょう:
write(socket、&struct_var、sizeof(struct_var));