[c#] Как изменить порядок байт при сериализации структуры LE-__m_GT
вот тут советуют руками всё преобразовывать http://stackoverflow.com/questions/3492304/c-encounter-a-pro...
Неужели нет чего-нибудь типа питоновской библиотерки Struct, в которой всё очень просто
Неужели нет чего-нибудь типа питоновской библиотерки Struct, в которой всё очень просто
i - это int(4)
h - это short(2)
>>> from struct import *
>>> pack("ih",1,2)
'\x01\x00\x00\x00\x02\x00'
>>> pack("!ih",1,2)
'\x00\x00\x00\x01\x00\x02'
>>>
где-то в инете нарыл вот такое
private static void RespectEndianness(Type type, byte[] data)
{
/*var fields = type.GetFields.Where(f => f.IsDefined(typeof(EndianAttribute false
.Select(f => new
{
Field = f,
Attribute = (EndianAttribute)f.GetCustomAttributes(typeof(EndianAttribute false)[0],
Offset = Marshal.OffsetOf(type, f.Name).ToInt32
}).ToList;*/
FieldInfo[] fields = type.GetFields;
foreach (FieldInfo field in fields)
{
int offset = Marshal.OffsetOf(type, field.Name).ToInt32;
if (BitConverter.IsLittleEndian)
{
Array.Reverse(data, offset, Marshal.SizeOf(field.FieldType;
}
}
}
public static T BytesToStruct<T>(byte[] rawData) where T : struct
{
T result = default(T);
RespectEndianness(typeof(T rawData);
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject;
result = (T)Marshal.PtrToStructure(rawDataPtr, typeof(T;
}
finally
{
handle.Free;
}
return result;
}
public static byte[] StructToBytes<T>(T data) where T : struct
{
byte[] rawData = new byte[Marshal.SizeOf(data)];
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject;
Marshal.StructureToPtr(data, rawDataPtr, false);
}
finally
{
handle.Free;
}
RespectEndianness(typeof(T rawData);
return rawData;
}
что-то извратное
один раз пишутся функции pack/unpack, которые используя reflection, ipaddress.NetworkToHostOrder/HostToNetworkOrder, binaryreader/writer - распаковывают или запаковывают структуры в последовательность байт
один раз пишутся функции pack/unpack, которые используя reflection, ipaddress.NetworkToHostOrder/HostToNetworkOrder, binaryreader/writer - распаковывают или запаковывают структуры в последовательность байт
ок. понял.
вопрос такой.
есть структура
хочу, чтобы она занимала ровно 4 + 2 + 10 байт. Как её определить?
Вот это ругается на то, что FieldOffset ==6 для char[]. Нужно 8 ставить.
можно сделать так
Хочу в итоге получить такой код.
Возможно такое?
очень хочется,чтобы всё исследование объекта выполнялось один раз, а в pack и unpack не было проверок на соответсвие типов, приведений и т.д.
Я не силён в терминологии, но надеюсь, что мысль изложил доступно.
вопрос такой.
есть структура
struct myStruct
{
int ID;
short time;
char name[10];
}
хочу, чтобы она занимала ровно 4 + 2 + 10 байт. Как её определить?
Вот это ругается на то, что FieldOffset ==6 для char[]. Нужно 8 ставить.
[StructLayout(LayoutKind.Explicit, Pack = 1, CharSet = CharSet.Ansi)]
public struct Data3
{
[FieldOffset(0)]
public int ID;
[FieldOffset(4)]
public short time;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
[FieldOffset(6)]
public char[] name;
}
можно сделать так
Хочу в итоге получить такой код.
Packet pt = new Packet<Data3>
Data3 vasya = new Data3
one.ID = 20;
one time = 10;
one name = "oooone";
pt.pack(one)
two.ID = 30;
two time = 10;
two name = "twooooo";
pt.pack(two)
Возможно такое?
очень хочется,чтобы всё исследование объекта выполнялось один раз, а в pack и unpack не было проверок на соответсвие типов, приведений и т.д.
Я не силён в терминологии, но надеюсь, что мысль изложил доступно.
как сдвинуть строку, я нашёл. Как-то всё очень извращённо получается.
[StructLayout(LayoutKind.Explicit, Pack = 1, CharSet = CharSet.Ansi)]
public unsafe struct Data2
{
private const int BUFFER_SIZE = 100;
[FieldOffset(0)]
public int ID;
[FieldOffset(4)]
public short Date;
[FieldOffset(6)]
public fixed byte name[BUFFER_SIZE];
}
забудь про marshal и соответственно про аттрибуты FieldOffset, StructLayout, fixed и т.д.
сделай свой pack/unpack через reflection
сделай свой pack/unpack через reflection
всё. понял, о чём ты.
про unsafe выше - это я не туда полез, да.
про unsafe выше - это я не туда полез, да.
для своего пакера из штатных нужен только аттрибут StructLayout с LayoutKind.Sequential, который вешается на класс.
это необходимо, чтобы поля не перемешивались, когда их получаешь через x.GetType.GetFields
это необходимо, чтобы поля не перемешивались, когда их получаешь через x.GetType.GetFields
Погоди, а как в структуре задать фиксированную длину byte[] ?
GetType тормознуто работает же.
я хочу, чтобы в pack /unpack эти функции не вызывались.
У меня есть идея, но она тянет на какой-то жёсткий хак.
можно получить сериализованные данные структуры, но они будут в LE.
Теперь, один раз разбираем структуру и смотрим, какие байты нужно поменять.
сериализованные данные и применяем уже сгенерированные правила к ней.
я хочу, чтобы в pack /unpack эти функции не вызывались.
У меня есть идея, но она тянет на какой-то жёсткий хак.
можно получить сериализованные данные структуры, но они будут в LE.
Теперь, один раз разбираем структуру и смотрим, какие байты нужно поменять.
сериализованные данные и применяем уже сгенерированные правила к ней.
[StructLayout(LayoutKind.Sequential)]
class Data3
{
public int Id;
public short Date;
[MyPackAttribute(Size=6)]
public string Name;
}
class Packer
{
public void Pack(BinaryWriter writer, object data)
{
foreach (var field in data.GetType.GetFields(..
{
if (field.FieldType == typeof(int
writer.Write(IPAddress.HostToNetworkOrderint)field.GetValue(data;
else if (field.FieldType == typeof(short
writer.Write(IPAddress.HostToNetworkOrdershort)field.GetValue(data;
else if (field.FieldType == typeof(string
{
var s = (string)field.GetValue;
var size = field.Attributes.OfType<MyPackAttribute>.First.Size ? s.Length;
for (var i = 0; i < size; ++i)
{
if (i < s.Length)
writer.Write(s[i]);
else
writer.Writechar)0);
}
}
}
}
}
самое унылое, что для каждого атомарного типа надо добавить свою ветку, но это делается один раз
>GetType тормознуто работает же.
GetType еще нет, вот GetFields и получение аттрибутов уже да.
поэтому обычно получение GetFields и аттрибутов делается один раз, переводится в свой формат и кэшируется в Dictionary<Type, MyPackFormatInfo>
если нужна очень высокая скорость, то для каждого типа через emit генерится пакер/unpacker и кэшируется уже такой packer.
GetType еще нет, вот GetFields и получение аттрибутов уже да.
поэтому обычно получение GetFields и аттрибутов делается один раз, переводится в свой формат и кэшируется в Dictionary<Type, MyPackFormatInfo>
если нужна очень высокая скорость, то для каждого типа через emit генерится пакер/unpacker и кэшируется уже такой packer.
ух ты. готовое решение
фишку с MyPackAttribute догнал. круто.
спасибо!
фишку с MyPackAttribute догнал. круто.
спасибо!
если нужна очень высокая скорость, то для каждого типа через emit генерится пакер/unpвот это наверно я про это и думал. Тут даже предложили просто для каждой стуктуры по паре функций написать.
pack_struct1(.. unpack_struct1(.. pack_struct2(.. unpack_struct2(..).
>вот это наверно я про это и думал. Тут даже предложили просто для каждой стуктуры по паре функций написать.
это окупается если общение будет локальное через shared memory.
как только появляется сеть, то весь наносекундный выигрыш съедают миллисекундные задержки в сети.
> ут даже предложили просто для каждой стуктуры по паре функций написать. pack_struct1(.. unpack_struct1(.. pack_struct2(.. unpack_struct2(..).
один из вариантов, что эти функции генерятся на этапе компиляции, с помощью кода аналогичному вышеприведенному
это окупается если общение будет локальное через shared memory.
как только появляется сеть, то весь наносекундный выигрыш съедают миллисекундные задержки в сети.
> ут даже предложили просто для каждой стуктуры по паре функций написать. pack_struct1(.. unpack_struct1(.. pack_struct2(.. unpack_struct2(..).
один из вариантов, что эти функции генерятся на этапе компиляции, с помощью кода аналогичному вышеприведенному
Сейчас обычно через создание Expression и Compile. особенно если .net 4.0 можно использовать
Вот реально, что пугает в .NET'е (давненько уже ничего не писал на нем так это то, что вот в плюсах тебе что-нибудь надо, ну ты берешь и пишешь, если это не что-то сильно большое или если оно не будет общаться с чем-то внешним (ну там, xml какой-нибудь). А в .NET'е как-то аж не по себе становится от того, что приходится программировать, т.е. кажется, что там все уже реализовано до нас.
Оставить комментарий
Phoenix
Хочу передать стркутуру по сети.что-то вроде
send(sock, &msg, sizeof(msg 0);
Возникает проблема с порядком байт на винде. Хочу чтобы был сетевой порядок порядок(big endian, как я понял который не на винде(там little endian).
(int) 1 -> 00 00 00 01, а не 01 00 00 00.
в с# нарыл такое.
Но и там, и там порядок байт не тот, который нужен.
Что делать?