Reputation: 2315
What is the best way to get a byte array from a struct to send over TCP sockets? I'm using .Net (VB or C#).
Upvotes: 2
Views: 5532
Reputation: 51224
One option is to marshal the native representation of the struct into a buffer directly, similar to how memcpy
works in C.
You would need to add the appropriate attribute to your struct,
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack=1)]
Then you can serialize it using:
/// <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;
}
Still, this is by far the least portable solution. Both sides will need to use the same alignment and endianness, and you will need to implement versioning yourself if you will ever need to change the struct itself.
In most cases, your serialization format shouldn't be a direct copy of your internal data structures.
Upvotes: 8
Reputation: 899
Why not just use a binary reader to populate fields of the struct, and read them out again? All you need to know is the size of the fields in the struct and it's position in the stream, no need for unmanaged solutions.. Here's an example from a waveplayer I wrote..
/// <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;
}
Upvotes: 2
Reputation: 415790
You should look into Serialization. There are number of options available to you, from Protocol Buffers (implementations by the 1st and 2nd ranked SO users) to Xml to the BinaryFormatter.
Upvotes: 3
Reputation: 623
I'm assuming the C language since you say "struct"
you can use a function called
ssize_t write(int fd, const void *buf, size_t count);
where FD is the filedescriptor of socket the buffer is the address of the structure, and count is the size in bytes
you would use it as:
write(socket,&struct_var, sizeof(struct_var));
Upvotes: 0
Reputation: 32831
If you are willing to take care of the endian (to communicate in an heterogeneous network), the only way to do this is field by field.
Upvotes: 1
Reputation: 399833
You need to be more specific and tell us your language.
For many languages, there are ready-made frameworks, or even parts of the language's standard environment, for doing these kinds of things.
Upvotes: 0