Парсинг двоичных данных в C?

Поток переходит в состояние ожидания, когда он вызывает wait() объекта. Это называется Ожидающее состояние. Когда поток достигнет состояния ожидания, ему придется подождать до некоторого другого потока notify() или notifyAll() на объекте.

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

После того, как останутся другие потоки и вероятность этого потока, он переходит в состояние Runnable после того, как он имеет право на получение работы на основе механизма потоковой передачи JVM и переходит в состояние запуска.

19
задан kaybenleroll 26 November 2008 в 17:03
поделиться

9 ответов

Стандартный способ сделать это в C/C++ действительно бросает к структурам, как 'gwaredd' предположил

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

, Что когда-либо платформа Вы находитесь на Вас, должен читать Сетевое программирование Unix, Объем 1: Сокеты Сетевой API. Купите его, одолжите его, украдите его (жертва поймет, это похоже на еду кражи или что-то...), но действительно считайте его.

После чтения Stevens, большая часть из этого будет иметь намного больше смысла.

14
ответ дан 30 November 2019 в 01:56
поделиться

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

Порядок байтов : архитектура, которую Вы используете прямо сейчас, могла бы быть обратным порядком байтов, но Ваша следующая цель могла бы быть прямым порядком байтов. Или наоборот. Можно преодолеть это с макросами (ntoh и hton, например), но это - дополнительная работа, и Вы имеете, удостоверяются, что Вы называете их макросами каждый раз , Вы ссылаетесь на поле.

Выравнивание : архитектура, которую Вы используете, могла бы быть способна к загрузке слова mutli-байта при нечетно обращенном смещении, но много архитектуры не могут. Если 4-байтовое слово колеблется между 4-байтовой границей выравнивания, загрузка может вытянуть мусор. Даже если сам протокол не имеет неправильно выровненных слов, иногда сам поток байтов неправильно выравнивается. (Например, хотя определение заголовка IP помещает все 4-байтовые слова на 4-байтовые границы, часто заголовок Ethernet продвигает сам заголовок IP на 2-байтовую границу.)

Дополнение : Ваш компилятор мог бы принять решение упаковать Вашу структуру плотно без дополнения, или это могло бы вставить дополнение для контакта с ограничениями выравнивания цели. Я видел это изменение между двумя версиями того же компилятора. Вы могли использовать #pragmas для принуждения проблемы, но #pragmas являются, конечно, определенными для компилятора.

Порядок битов : упорядочивание битов в битовых полях C является определенным для компилятора. Плюс, биты трудно "достигнуть" для Вашего кода во время выполнения. Каждый раз, когда Вы ссылаетесь на битовое поле в структуре, компилятор должен использовать ряд маски/операций сдвига. Конечно, Вы оказываетесь перед необходимостью делать то маскирование/смещение в какой-то момент, но лучше всего не сделать это в каждой ссылке, если скорость является беспокойством. (Если пространство является переопределяющим беспокойством, то используйте битовые поля, но действуйте осторожно.)

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

typedef struct _MyProtocolData
{
    Bool myBitA;  // Using a "Bool" type wastes a lot of space, but it's fast.
    Bool myBitB;
    Word32 myWord;  // You have a list of base types like Word32, right?
} MyProtocolData;

Void myProtocolParse(const Byte *pProtocol, MyProtocolData *pData)
{
    // Somewhere, your code has to pick out the bits.  Best to just do it one place.
    pData->myBitA = *(pProtocol + MY_BITS_OFFSET) & MY_BIT_A_MASK >> MY_BIT_A_SHIFT;
    pData->myBitB = *(pProtocol + MY_BITS_OFFSET) & MY_BIT_B_MASK >> MY_BIT_B_SHIFT;

    // Endianness and Alignment issues go away when you fetch byte-at-a-time.
    // Here, I'm assuming the protocol is big-endian.
    // You could also write a library of "word fetchers" for different sizes and endiannesses.
    pData->myWord  = *(pProtocol + MY_WORD_OFFSET + 0) << 24;
    pData->myWord += *(pProtocol + MY_WORD_OFFSET + 1) << 16;
    pData->myWord += *(pProtocol + MY_WORD_OFFSET + 2) << 8;
    pData->myWord += *(pProtocol + MY_WORD_OFFSET + 3);

    // You could return something useful, like the end of the protocol or an error code.
}

Void myProtocolPack(const MyProtocolData *pData, Byte *pProtocol)
{
    // Exercise for the reader!  :)
}

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

30
ответ дан 30 November 2019 в 01:56
поделиться

Парсинг/форматирование двоичных структур является одним из очень немногие вещи, который легче сделать в C, чем на высокоуровневых/управляемых языках. Вы просто определяете структуру, которая соответствует формату, который Вы хотите обработать, и структура синтаксический анализатор/средство форматирования. Это работает, потому что структура в C представляет точное расположение памяти (который является, конечно, уже двоичным). См. также ответы kervin и gwaredd.

2
ответ дан 30 November 2019 в 01:56
поделиться

Вы могли бы интересоваться Google Protocol Buffers , который является в основном платформой сериализации. Это, прежде всего, для C++/Java/Python (это - языки, поддерживаемые Google), но существуют продолжающиеся усилия портировать его на другие языки, включая C. (Я не использовал порт C вообще, но я ответственен за один из портов C#.)

5
ответ дан 30 November 2019 в 01:56
поделиться

Вы не должны действительно анализировать двоичные данные в C, просто бросать некоторый указатель на то, что Вы думаете, что это должно быть.

struct SomeDataFormat
{
    ....
}

SomeDataFormat* pParsedData = (SomeDataFormat*) pBuffer;

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

3
ответ дан 30 November 2019 в 01:56
поделиться

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

Редактирование :
хорошо, поэтому после чтения Jon , которым кажется ответ, существует библиотека, хорошо вид библиотеки, это больше похоже на инструмент генерации кода. Но как многие указанные просто кастинг данных соответствующей структуре данных, с соответствующей заботливостью т.е. использованием упакованных структур и заботящийся о проблемах порядка байтов Вы хороши. Используя такой инструмент с C это - просто излишество.

1
ответ дан 30 November 2019 в 01:56
поделиться

По моему опыту, лучший способ состоит в том, чтобы сначала записать ряд примитивов к чтению-записи единственное значение некоторого типа от двоичного буфера. Это дает Вам высокую видимость и очень простой способ обработать любые проблемы порядка байтов: просто заставьте функции сделать его правильно.

Затем можно, например, определить struct с для каждого из сообщений протокола, и запись упаковывает/распаковывает (некоторые люди называют их, сериализируют/десериализовывают), функции для каждого.

Как основной случай, примитив для извлечения единственного 8-разрядного целого числа мог быть похожим на это (принятие 8-разрядного char на хост-машине, Вы могли добавить слой пользовательских типов, чтобы гарантировать что также, в случае необходимости):

const void * read_uint8(const void *buffer, unsigned char *value)
{
  const unsigned char *vptr = buffer;
  *value = *buffer++;
  return buffer;
}

Здесь, я принял решение возвратить значение ссылкой и возвратить обновленный указатель. Это - вопрос вкуса, Вы могли, конечно, возвратить значение и обновить указатель ссылкой. Это - ключевая роль дизайна, что функция чтения обновляет указатель, для создания их chainable.

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

const void * read_uint16(const void *buffer, unsigned short *value)
{
  unsigned char lo, hi;

  buffer = read_uint8(buffer, &hi);
  buffer = read_uint8(buffer, &lo);
  *value = (hi << 8) | lo;
  return buffer;
}

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

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

10
ответ дан 30 November 2019 в 01:56
поделиться

Позвольте мне вновь заявить о Вашем вопросе видеть, понял ли я правильно. Вы ищете программное обеспечение, которое возьмет формальное описание пакета и затем произведет "декодер" для парсинга таких пакетов?

Если так, ссылка в том поле КЛАВИАТУРЫ . Хорошая статья, представляющая его, КЛАВИАТУРЫ: Проблемно-ориентированный Язык для Обработки Специальных Данных . КЛАВИАТУРЫ очень завершены, но к сожалению в соответствии с небесплатной лицензией.

существуют возможные альтернативы (я не упоминал non-C решения). По-видимому, ни один не может рассматриваться как абсолютно готовый к производству:

, Если Вы читаете на французском языке, я суммировал эти проблемы в двоичные файлы GГ©nГ©ration de dГ©codeurs de formats .

12
ответ дан 30 November 2019 в 01:56
поделиться

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

Для контакта с порядком байтов выходит, сетевой порядок байтов был представлен - обычная практика должна преобразовать числа от порядка байтов хоста до сетевого порядка байтов прежде, чем отправить данные и преобразовать назад для хостинга порядка по получении. Посмотрите функции htonl, htons, ntohl и ntohs.

И действительно полагают, что совет kervin - читал UNP.Вы не пожалеете об этом!

1
ответ дан 30 November 2019 в 01:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: