Парсинг бинарных сообщений
От: Flem1234  
Дата: 18.10.21 13:40
Оценка:
Иногда мне приходится писать раного рода парсеры для двоичный форматов. Почти всегда это работа по сети с разными устройствами по разным протоколам. Для примера возьмем netSDR — протокол работы с цифровыми приемниками. https://www.moetronix.com/files/NetSdrInterfaceSpec105.pdf
Парсеры должны быть довольно быстрыми и просто написанными (для того чтобы ошибки были маловероятны, легко находимы и устранимы).

Но я не могу выработать для себя идельный набор best practices.
Мой последний список такой
Пока не ясные моменты:
Какие правилами, практиками вы пользуетесь?
Какие практики и правила кажутся вам уместными?
Re: Парсинг бинарных сообщений
От: _FRED_ Черногория
Дата: 18.10.21 14:42
Оценка:
Здравствуйте, Flem1234, Вы писали:

F>Но я не могу выработать для себя идельный набор best practices.

F>Мой последний список такой
F>Использовать события C# для генерации

В смысле `event`!?

F>Пока не ясные моменты:

F>Кажется уместным по соображениям удобстра комбинирования событий использовать IObservable<T>, но метод OnNext(T) не допускает передачи параметров по ссылке (ref или in), что меня расстраивает)

Можно использовать массивы (например) из пула — копировать в них разобранные спаны, отдавать на обработку, потом возвращать в пул.

F>Для некоторых сообщений общий формат такой

F>8 bit Length lsb , 3 bit type 5 bit Length msb, потом N байт тела сообщения.
F>Приходится делать событие OnDataMessageReceived(TypeAsEnum messageType, int len, Span<byte> dataBytes), а потом реинтерпритировать dataBytes в зависимости от типа. Хочется иметь событие OnDataMessageReceived(in
F>ТутКакойТоТипСПолями1Тип2Длина3Данные data). Но структуру неизвестного во время компиляции размера не объявишь, не особо страшно но хочется идеала)

А как вы собираетесь написать код для обработки "структуры неизвестного во время компиляции размера"?

Мне кажется удобным по типу сообщения создать структуру, в которую передаётся спан и другое необходимое и внутри неё уже этот спан парсить, оттадавая вовне интерпретацию байтов/чаров в зависимости от типа.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Парсинг бинарных сообщений
От: Flem1234  
Дата: 18.10.21 15:08
Оценка:
Здравствуйте, _FRED_, Вы писали:

F>>Использовать события C# для генерации


_FR>В смысле `event`!?


Да, а что?

F>>Пока не ясные моменты:

F>>Кажется уместным по соображениям удобстра комбинирования событий использовать IObservable<T>, но метод OnNext(T) не допускает передачи параметров по ссылке (ref или in), что меня расстраивает)

_FR>Можно использовать массивы (например) из пула — копировать в них разобранные спаны, отдавать на обработку, потом возвращать в пул.


Да, так и есть — пулы везде.

_FR>А как вы собираетесь написать код для обработки "структуры неизвестного во время компиляции размера"?

Так далеко моя мысль еще не заходила) Самый распространенный случай — это сообщение в заголовке содержит длину массива, а в теле сам массив. Но длина может быть разная для разных устройств и т.п.

_FR>Мне кажется удобным по типу сообщения создать структуру, в которую передаётся спан и другое необходимое и внутри неё уже этот спан парсить, оттадавая вовне интерпретацию байтов/чаров в зависимости от типа.

Так и делаю.

Основная проблема при этом то, что протоколы, в общем-то похожи друг на друга, форматы сообщений тоже. Но нет совершенства, все думаю как бы сделать лучше)
Re: Парсинг бинарных сообщений
От: Vladek Россия Github
Дата: 18.10.21 15:21
Оценка: 2 (1)
Здравствуйте, Flem1234, Вы писали:

F>Какие правилами, практиками вы пользуетесь?

F>Какие практики и правила кажутся вам уместными?

Для эффективного чтения устройств можно посмотреть что-то полезное тут.

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

Парсер, чтобы быть эффективным, должен заранее уметь разбирать всех форматы входящих сообщений. Его удобно разделить на сканер и построитель. Задача сканера — скопировать тело сообщения в свой буфер (тут пригодится ArrayPool<T>, пример использования или что-то вроде этого) и выбрать правильный построитель сообщения. Задача построителя — собственно разобрать тело сообщения (буфер сканера) и сформировать объект сообщения с конкретным типом (либо создавать их, либо повторно использовать объекты из пула). Сканер и построитель имеют только синхронный код и работают с ReadonlySequence/Memory/Span.

Для чтения сообщений можно использовать новый API Channels.
Re: Парсинг бинарных сообщений
От: _NN_ www.nemerleweb.com
Дата: 18.10.21 16:47
Оценка:
Здравствуйте, Flem1234, Вы писали:

F>Иногда мне приходится писать раного рода парсеры для двоичный форматов. Почти всегда это работа по сети с разными устройствами по разным протоколам. Для примера возьмем netSDR — протокол работы с цифровыми приемниками. https://www.moetronix.com/files/NetSdrInterfaceSpec105.pdf

F>Парсеры должны быть довольно быстрыми и просто написанными (для того чтобы ошибки были маловероятны, легко находимы и устранимы).

Чтобы ошибки были маловероятными будет уместно задействовать кодогенерацию и декларативное описание как сделано в Kaitai.
У библиотеки, к сожалению, есть описанные вами недостатки, т.к. разрабатывалась она до появления Span-ов.
Но это легко решаемо через правки библиотеки или через пост обработку кода.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Парсинг бинарных сообщений
От: Flem1234  
Дата: 18.10.21 17:25
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Чтобы ошибки были маловероятными будет уместно задействовать кодогенерацию и декларативное описание как сделано в Kaitai.


Да, я смотрел в сторону Kaitai. Если есть опыт, поделитесь, пожалуйста. Интересует универсальность — можно ли описать большую часть бинарных форматов и что делать если не получается выразить что-то декларативно. Например, в некоторых протоколах встречались выражения по типу — длина тела пакета считается по формуле: длина заголовка (два варианта в зависимости от версии протокола) плюс длина подзаговока, плюс количество элементов в массиве значений умноженных на 4 (размер элемента).
Идея Kaitai мне нравится)
Re[3]: Парсинг бинарных сообщений
От: _NN_ www.nemerleweb.com
Дата: 18.10.21 17:44
Оценка: 10 (1) +1
Здравствуйте, Flem1234, Вы писали:

F>Здравствуйте, _NN_, Вы писали:


_NN>>Чтобы ошибки были маловероятными будет уместно задействовать кодогенерацию и декларативное описание как сделано в Kaitai.


F>Да, я смотрел в сторону Kaitai. Если есть опыт, поделитесь, пожалуйста. Интересует универсальность — можно ли описать большую часть бинарных форматов и что делать если не получается выразить что-то декларативно. Например, в некоторых протоколах встречались выражения по типу — длина тела пакета считается по формуле: длина заголовка (два варианта в зависимости от версии протокола) плюс длина подзаговока, плюс количество элементов в массиве значений умноженных на 4 (размер элемента).

F>Идея Kaitai мне нравится)

Формат описания данных очень крутой.
Можно описать практически всё.
Из недостатков это нет поддержки нулевых ссылок и повсеместное использование массивов вместо Span.
Мы решили это пост обработкой генерируемого кода.

По хорошему конечно лучше решить это правкой библиотеки
http://rsdn.nemerleweb.com
http://nemerleweb.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.