Сопоставление структур памяти в С#, оно того стоит? Или есть лучший способ

Я отправляю несколько пакетов данных по сети, и они приходят в байтах [] с, скажем, структура

[целое, целое, байт, целое]

Если бы это был С++, я бы объявил struct* и указал на byte[]. Я делаю этот проект на С#, и я не уверен, стоит ли оно того с упорядочиванием накладных расходов или есть лучший способ справиться с этим на С#, я весь в ушах.

  • обновить, для ясности

По сути, что он делает Маршалинг массива байтов в структуру C# Только мне интересно, стоит ли оно того.


person dpington    schedule 04.06.2011    source источник
comment
Какой функции вы передаете этот массив байтов? Можете ли вы показать нам остальную часть кода? Мне трудно понять, чего именно вы пытаетесь достичь. (И как получить byte[] из структуры, содержащей byte.)   -  person Cody Gray    schedule 04.06.2011


Ответы (4)


Я думаю, что маршалинг - лучший вариант. Вы можете проанализировать массив байтов самостоятельно, используя BitConverter, но это потребует дополнительной работы с вашей стороны и не столь гибко.

person svick    schedule 04.06.2011

Единственная реальная причина сделать это таким образом — выжать из системы все до последнего бита производительности. На мой взгляд, вам лучше написать его с помощью BitConverter, чтобы убедиться, что он работает. Затем, если получение данных является узким местом в производительности, рассмотрите возможность маршалинга.

Например, учитывая структуру:

struct MyStruct
{
    private int f1;
    private int f2;
    private byte f3;
    private int f4;
    public MyStruct(int i1, int i2, byte b1, int i4)
    {
        f1 = i1;
        f2 = i2;
        f3 = b1;
        f4 = i4;
    }
    // assume there are public get accessors
}

Затем вы можете создать новый из буфера с помощью:

var s = new MyStruct(BitConverter.ToInt32(buff, 0),
    BitConverter.ToInt32(buff, 4),
    BitConverter.ToUInt8(buff, 8),
    BitConverter.ToInt32(buff, 9));

Это намного проще написать и проверить, чем маршалинг, и, вероятно, будет достаточно быстро для ваших нужд.

person Jim Mischel    schedule 04.06.2011
comment
Довольно сложно убедиться, что смещения правильные, данные переменной длины и более 4 полей для протокола. - person dpington; 04.06.2011

Ну, я думаю, у каждого есть свой «любимый» способ. При получении блоков протокола через поток байтов на любом объектно-ориентированном языке я обычно запускаю каждый полученный байт в экземпляр класса «ProtocolUnit», вызывая его метод «bool addByte()». Конечный автомат в классе обрабатывает байты и проверяет собранные поля на наличие ошибок/состояний. Если ProtocolUnit был получен полностью, функция метода addByte() возвращает значение true, чтобы указать вызывающей стороне, что PDU был правильно собран. Обычно экземпляр затем ставится в очередь тому, кто будет его обрабатывать, и создается новый ProtocolUnit (или депулируется), чтобы он мог начать сборку следующего PDU.

Неявно подразумевается, что начало сообщения может быть идентифицировано, так что в случае ошибки машина состояний может либо сбросить себя, сбрасывая ошибочные данные, либо возвращая «true» вызову addByte(), устанавливая подходящее сообщение об ошибке, которое вызывающая сторона может проверить, чтобы решить, что делать (например, если свойство errorMess равно "", тогда очередь в обработчик, иначе очередь в регистратор ошибок).

Я уверен, что вы считаете это огромным излишеством, но это работает для меня :)

С уважением, Мартин

PS старайтесь избегать протоколов, в которых длина передается в начале и это единственный способ определить начало/конец сообщения. Это очень хрупкий и подверженный взрыву, особенно с незащищенными транспортами, такими как UDP. Даже с TCP я знал маршрутизатор x****x, который время от времени добавлял нуль к пакетам...

person Martin James    schedule 04.06.2011

В качестве альтернативы BitConverter заверните каждый byte[] в MemoryStream и извлеките поля, используя BinaryReader. Аналогично, но поток поддерживает смещения для вас.

person anton.burger    schedule 08.06.2011