A
amdrit
I am facing an issue where I need to pass data between a client and server
using sockets. I want to minimize bloat in my objects being passed so I was
attempting to use structs. However, in the struct, there is a byte array
that should be variable in length. According to everything I read I must
use a MarshalAs attribute and set a constant size for the data. In my
scenario I would be passing a portion of a given file based on buffer size
in the byte array.
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct Message
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string BatchID;
public int MessageType;
[MarshalAs( UnmanagedType.ByValArray, SizeConst=?? )]
public byte[] data; //Holds the file fragment
}
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct FileFragment
{
public int PageNumber;
public int Offset;
public int Length;
[MarshalAs( UnmanagedType.ByValArray, SizeConst=?? )]
public byte[] Data; //(Buffer Size - len(Message) - Len(Other Fields in
FileFragment))
}
I plan to allow the buffer size to be configurable for bandwidth throttling
so FileFragment will be variable based on that. Plus if I reach the end of
the file and have fewer bytes than the buffer size, the array would be
smaller as well.
I could convert this to a class and use a binary formatter to bypass my
problem, but then I would have a lot of extra header information in the data
and feel that I would be supplanting my goal. I suppose I could create a
method to manually create a byte array from the structures and then manually
reconstruct the structures on the other side. However, I was under the
impression that I have to pin this data so GC wont attempt to collect the
data.
public byte[] ToByteArray(Message msg)
{
List<byte> data = new List<byte>();
byte[] dataBytes;
data.AddRange(System.Text.ASCIIEncoding.ASCII.GetBytes(msg.BatchID));
data.AddRange(BitConverter.GetBytes(msg.MessageType));
data.AddRange(msg.data);
dataBytes = data.ToArray();
return dataBytes;
}
public byte[] ToByteArray(FileFragment ff)
{
List<byte> data = new List<byte>();
byte[] dataBytes;
data.AddRange(BitConverter.GetBytes(ff.PageNumber));
data.AddRange(BitConverter.GetBytes(ff.Offset));
data.AddRange(BitConverter.GetBytes(ff.Length));
data.AddRange(ff.Data);
dataBytes = data.ToArray();
return dataBytes;
}
public Message FromByteArray(byte[] data)
{
Message msg = new Message();
msg.BatchID = System.Text.ASCIIEncoding.ASCII.GetString(data, 0, 32);
msg.MessageType = BitConverter.ToInt32(data, 32);
data.CopyTo(msg.data, 36);
return msg;
}
public FileFragment FromByteArray(Message msg)
{
FileFragment ff = new FileFragment();
ff.PageNumber = BitConverter.ToInt32(msg.data, 0);
ff.Offset = BitConverter.ToInt32(msg.data, 4);
ff.Length = BitConverter.ToInt32(msg.data, 8);
msg.data.CopyTo(ff.Data, 12);
return ff;
}
Do you have any recommendations about this issue?
using sockets. I want to minimize bloat in my objects being passed so I was
attempting to use structs. However, in the struct, there is a byte array
that should be variable in length. According to everything I read I must
use a MarshalAs attribute and set a constant size for the data. In my
scenario I would be passing a portion of a given file based on buffer size
in the byte array.
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct Message
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string BatchID;
public int MessageType;
[MarshalAs( UnmanagedType.ByValArray, SizeConst=?? )]
public byte[] data; //Holds the file fragment
}
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct FileFragment
{
public int PageNumber;
public int Offset;
public int Length;
[MarshalAs( UnmanagedType.ByValArray, SizeConst=?? )]
public byte[] Data; //(Buffer Size - len(Message) - Len(Other Fields in
FileFragment))
}
I plan to allow the buffer size to be configurable for bandwidth throttling
so FileFragment will be variable based on that. Plus if I reach the end of
the file and have fewer bytes than the buffer size, the array would be
smaller as well.
I could convert this to a class and use a binary formatter to bypass my
problem, but then I would have a lot of extra header information in the data
and feel that I would be supplanting my goal. I suppose I could create a
method to manually create a byte array from the structures and then manually
reconstruct the structures on the other side. However, I was under the
impression that I have to pin this data so GC wont attempt to collect the
data.
public byte[] ToByteArray(Message msg)
{
List<byte> data = new List<byte>();
byte[] dataBytes;
data.AddRange(System.Text.ASCIIEncoding.ASCII.GetBytes(msg.BatchID));
data.AddRange(BitConverter.GetBytes(msg.MessageType));
data.AddRange(msg.data);
dataBytes = data.ToArray();
return dataBytes;
}
public byte[] ToByteArray(FileFragment ff)
{
List<byte> data = new List<byte>();
byte[] dataBytes;
data.AddRange(BitConverter.GetBytes(ff.PageNumber));
data.AddRange(BitConverter.GetBytes(ff.Offset));
data.AddRange(BitConverter.GetBytes(ff.Length));
data.AddRange(ff.Data);
dataBytes = data.ToArray();
return dataBytes;
}
public Message FromByteArray(byte[] data)
{
Message msg = new Message();
msg.BatchID = System.Text.ASCIIEncoding.ASCII.GetString(data, 0, 32);
msg.MessageType = BitConverter.ToInt32(data, 32);
data.CopyTo(msg.data, 36);
return msg;
}
public FileFragment FromByteArray(Message msg)
{
FileFragment ff = new FileFragment();
ff.PageNumber = BitConverter.ToInt32(msg.data, 0);
ff.Offset = BitConverter.ToInt32(msg.data, 4);
ff.Length = BitConverter.ToInt32(msg.data, 8);
msg.data.CopyTo(ff.Data, 12);
return ff;
}
Do you have any recommendations about this issue?