2009-05-12 5 views
5

Я отправляю и получаю двоичные данные на/из устройства в пакетах (64 байт). Данные имеют конкретный формат, часть которого зависит от разных запросов/ответов.Как интерпретировать двоичные данные в C++?

Теперь я проектирую интерпретатор для полученных данных. Простое чтение данных по позициям в порядке, но не выглядит так круто, когда у меня есть десяток различных форматов ответов. В настоящее время я думаю о создании нескольких структур для этой цели, но я не знаю, как это будет происходить с заполнением.

Возможно, есть лучший способ?


Похожие:

+0

Я был уверен, что видел почти дубликат этого, но я не мог его выкопать. Ответы в соответствующей ссылке не очень хорошие, как здесь, но все же ... – dmckee

ответ

3

Я делал это бесчисленное количество раз раньше: это очень распространенный сценарий. Есть несколько вещей, которые я практически всегда делаю.

Не беспокойтесь о том, чтобы сделать его наиболее эффективным.

Если мы действительно тратим много времени на упаковку и распаковку пакетов, мы всегда можем изменить его, чтобы быть более эффективным. Пока я не сталкивался с ситуацией, когда мне еще нужно было, я не реализовал сетевые маршрутизаторы!

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

Я часто ветер с архитектурой, включая следующие виды вещей:

  • пакета, базовый класс. Любые общие поля данных доступны (но не изменяются).Если данные не хранятся в упакованном формате, то есть виртуальная функция, которая будет создавать упакованный пакет.
  • Несколько классов представления для определенных типов пакетов, полученных из общего типа пакета. Если мы используем функцию упаковки, то каждый класс представления должен ее реализовать.
  • Все, что может быть выведено из определенного типа класса представления (то есть идентификатор типа пакета из общего поля данных), рассматривается как часть инициализации и в остальном не может быть изменено.
  • Каждый класс презентации может быть создан из распакованного пакета или будет изящно сбой, если пакетные данные недействительны для этого типа. Это может быть завершено на заводе для удобства.
  • Если у нас нет доступного RTTI, мы можем получить «RTTI от бедного человека», используя идентификатор пакета, чтобы определить, какой именно класс презентации действительно является объектом.

Во всех случаях это возможно (даже если они предназначены только для отладочных сборников), чтобы убедиться в том, что каждое изменяемое поле устанавливается на значение разумного значения. Хотя это может показаться большой работой, очень сложно иметь неверно отформатированный пакет, содержимое предварительно упакованных пакетов может быть легко проверено глазом с помощью отладчика (так как это все в обычных переменных формата платформы).

Если нам нужно реализовать более эффективную схему хранения, это тоже можно обернуть в эту абстракцию с небольшими дополнительными затратами на производительность.

+0

Этот тип дизайна очень хорошо работает для потоков данных, которые закодированы в ASN.1. Просто реализовал что-то подобное себе для анализа LDAP – Matt

3

Это трудно сказать, что самое лучшее решение, не зная точный формат (ы) данных. Считаете ли вы использование профсоюзов?

+0

Спасибо! Очень хорошая идея, хотя мне все равно нужна структура или даже пара. –

+3

Я думаю, что он подразумевал структуры и союзы, используемые вместе. Но все же могут быть проблемы, связанные с отверстиями в конструкции. –

8

Вам необходимо использовать структуры и/или объединения. Вам нужно убедиться, что ваши данные правильно упакованы с обеих сторон соединения, и вы можете перевести их в сетевой порядок и на каждом конце, если есть вероятность, что любая из сторон соединения может работать с другим порядок байтов.

В качестве примера:

#pragma pack(push) /* push current alignment to stack */ 
#pragma pack(1)  /* set alignment to 1 byte boundary */ 
typedef struct { 
    unsigned int packetID; // identifies packet in one direction 
    unsigned int data_length; 
    char   receipt_flag; // indicates to ack packet or keep sending packet till acked 
    char   data[]; // this is typically ascii string data w/ \n terminated fields but could also be binary 
} tPacketBuffer ; 
#pragma pack(pop) /* restore original alignment from stack */ 

, а затем при назначении:

packetBuffer.packetID = htonl(123456); 

, а затем при получении:

packetBuffer.packetID = ntohl(packetBuffer.packetID); 

Вот некоторые дискуссии Endianness и Alignment and Structure Packing

Если вы не упакуете структуру, она будет выравниваться с границами слов, а внутренняя компоновка структуры и ее размер будут неправильными.

+4

Помните, что на некоторых процессорах, таких как ARM, вы можете получить исключение выравнивания данных, если попытаетесь получить доступ к data_length в примере. – Steven

+0

@Steven хороший пункт. –

+0

Чтобы устранить проблему, Стивен упомянул о выравнивании данных, вам нужно добавить char pad [3]; после получения_flag. – zooropa

1

Я согласен с Wuggy. Вы также можете использовать генерацию кода для этого. Используйте простой файл определения данных, чтобы определить все ваши типы пакетов, а затем запустите над ним скрипт python для создания структур прототипов и функций сериализации/несериализации для каждого из них.

1

Это «готовое решение», но я бы предложил взглянуть на библиотеку Python construct.

Построить является Python библиотека для синтаксического анализа и построения данных структуры (бинарной или текстовой). Это на основе концепции определения данных структур в декларативном виде, , а не процедурного кода: больше сложные конструкции состоят из иерархии более простых из . Это первая библиотека , которая делает разбором веселья, вместо обычной головной боли сегодня.

Конструкция очень надежная и мощная, и только чтение учебника поможет вам лучше понять проблему. У автора также есть планы по автогенерации кода C из определений, поэтому он определенно стоит усилий для чтения.

Смежные вопросы