2012-05-31 2 views
1

Я разрабатываю приложение C для связи с одним из реальных устройств системы управления. Устройство использует четко определенную структуру протокола. Например, рассмотрим один из структуры, устройство посылает как пакет UDP при запросе: -Предложения по декодированию UDP-пакетов

typedef struct poll_request_s { 
    uint16    poll_number; /* poll number mirrored from the 
            * poll request */ 
    uint16    length;  /* length of the message */ 

    /* till above it was all header section this is ACTUAL DATA */ 
    attribute_list_t attr_list; /* this attribute list contains 
            * various attributes */ 
} poll_request_t 

Теперь attribute_list_t является структурой, которая упаковывает различные атрибуты и каждый атрибут в этом списке идентифицируется номером идентификатор, который uint16 (16-битное целое число). Таким образом, в коротком протоколе работает примерно так: -

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

Это atrtribute_list_t структура является то, как показано ниже: -

typdef struct attribute_list_s { 
    uint16 length;  /* length of attribute list */ 
    uint16 count;  /* number of attributes in this list */ 
    uint8 attrs_data[]; /* another container to hold attributes' data */ 
} attribute_list_t 

Теперь attrs_data только место держатель для хранения всех атрибутов в списке. Фактически этот attrs_data должен быть отлит в другую структуру, называемую ava_type, чтобы прочитать информацию об атрибутах.

typdef struct ava_type_s { 
    uint16 attr_id; /* type of attribute */ 
    uint16 length; /* length of this attribute 
        *(this length of single attribute not whole list*/ 
    uint8 data[]; /* another flexible array to hold data for this 
        * attribute type */ 
} 

Теперь для того, чтобы итерацию и разобрать атрибуты внутри этой структуры, я в настоящее время с помощью этого алгоритма (псевдо-код ниже):

uint8* packet = recv_packet(SOCKET); 
/* this is used as packet iterator pointer */ 
unit8* packet_ptr = packet; 
parsed_packet_t parsed_packet = malloc(SOME_SIZE); 
. 
. /* do header un-packing */ 
. 
/* dont need attribute_list length so skip this 2 bytes */ 
parsed_packet += 2; 

/* parsed packet do nee count of attributes */ 
parsed_packet.attribute_list->count = NTOHS(packet_ptr); 
packed_ptr += 2; /* skip count */ 

/* now packet_ptr is pointer to attr_list */ 
offset = 0, i = 0; 
for(i = 0 to attr_list->count) { 
    /* cast the attributes' data to ava_type */ 
    packet_ptr += offset; 

    /* parse object identifier */ 
    parsed_packet.attribute_list->data[i++].object_id = NTOHS(packet_ptr); 
    packet_ptr += 2; /* skip 2 bytes */ 

    /* next offset would be attribute length of this packet */ 
    attribute_length += 2 + NTOHS(packet_ptr); 
    packet_ptr += 2; 

    /* now we are pointer to actual data of i(th) attribute */ 

    /* I've made this parser structure and hash table to 
    * retrieve the parser for particular attr_id */ 
    parser* p = HASH_TABLE(ava_type->attr_id); 

    /* parser has function point for network order to host 
    * order and visa-versa */ 
    p->ntoh(ava_type, parsed_packet.attribute_list->data[i]); 
} 

Теперь мои вопросы:

  • Несмотря на то, что у меня есть метод HASH_TABLE, описанный выше, но на самом деле я использую от 20 до 30 IF-ELSE. Так как C не имеет hash table в stdlib. В протоколе порядка 600, и я не хочу писать 600 if-else. Какие предложения и методы вы дадите для разбора этой структуры в соответствии с их attribute_id.
  • Другая проблема - заполнение компилятора в структурах, которые я определил. Вся моя структура определяется полем flexible array для контейнера данных. Теперь, когда я получаю сообщение, они содержат length почти для каждого атрибута, но этот length не может использоваться для malloc..ing моей анализируемой структуры, поскольку компилятор может волшебным образом добавить несколько байтов paddings, и мне не хватает байтов. Обычно я malloc..ing около lenght + 300 байт для целей безопасности. На самом деле это выглядит плохой практикой управления памятью. Любые предложения по этой проблеме?

malloc..ing Структура для анализа полученных сообщений является самой большой проблемой для меня до сих пор. Я хочу, чтобы какая-то память была эффективной и быстрой для этого?

Кроме того, если вы уже сделали такие проекты, не могли бы вы поделиться своим подходом? Любые предложения или комментарии, чтобы поставить меня в правильном направлении? Я хочу простой дизайн, не усложняя вещи.

+0

отправка плохих мыслей на вас для бессмысленного использования типа – tbert

ответ

2

I strong рекомендовать не использовать C структуры для определения сетевого протокола. C макеты Struct зависят от:

  1. Аппаратные средства
  2. Компилятор
  3. версия компилятора
  4. Исходный код
  5. В #pragmas встроен в исходном коде, если какой-либо
  6. параметры компилятора, действующие при компиляции исходного кода.

Используйте XDR или что-то, что даст вам стандартный формат. Вы должны быть в состоянии точно определить, что у вас есть сейчас в XDR, и выполнить все кодирование и декодирование для вас автоматически.

+0

Спасибо за ответ! Это звучит интересно, но мне действительно нужно отфильтровать эти данные и выполнить некоторые логические операции и обновление графического интерфейса? Кажется, что XDR - это только способ представления данных? Могу ли я использовать это для управления устройством в режиме реального времени? Любые ссылки или дополнительная информация о XDR будут полезны. – Shivam

+0

XDR - представление данных eXternal. Это в основном язык определения интерфейса (IDL), который компилируется в код C, и вы можете писать свои собственные расширения. Вы можете использовать его для потоковой передачи или в вашем случае в памяти. Он ничего не делает. Он был частью SUN RPC. Насколько я знаю, он встроен в большинство Unix и Linux. Попробуйте 'man rpcgen'. Если протокол определен устройством, вы можете или не можете его сопоставить с XDR, но при быстром просмотре я ничего не вижу о том, что не будет отображаться. – EJP

+1

Я должен отметить, что это также можно сделать вручную, написав свои собственные функции flatten()/unflatten() для memcpy() каждое значение из вашей структуры в массив байтов и наоборот (необязательно с кодировкой endian-swapping также, если вы хотите это указать). Это немного утомительно, но делает ваш сетевой алгоритм независимым от компилятора gotchas EJP, указанного выше. –

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