Вступление


В чем прелесть XML? Он реализован под все платформы, «человекочитаемый», для него созданы схемы данных (условно человекочитаемые). Открывая 25-мегабайтный файл в браузере сразу замечаешь недостатки этого текстового формата, и начинаешь задумываться. Делаем мы это, конечно, не часто, но все же — чем бы заменить XML?

Добавление самопальных бинарных контейнеров в проект заканчивается провалом, когда к вам приходят партнеры и просят подключить их к этому каналу данных. Google Protobuf поначалу выглядит хорошо, но вскоре понимаешь, что это не замена для XML, не хватает функциональности. BSON в 5 раз медленнее Protobuf, уступает в компактности и для него не реализованы схемы данных.

Разработаем же еще один бинарный формат.

USDS 1.0


USDS (или $S) — Universal serialized data structures — универсальные сериализованные структуры данных, бинарный формат, способный полностью заменить XML и JSON. Основные отличия:

  • Вместо текстовых тегов/ключей используются целые числа. Соотношение «Имя» — «Целочисленный идентификатор» задается отдельно, в «Словаре». Словарь может быть прикреплен к документу USDS или может быть передан отдельно.
  • Нет закрывающих тегов, как в XML;
  • Документы USDS формируются строго по схеме, которая также задается в Словаре. Поддерживаются полиморфизм и опциональные поля.
  • Числовые значения в документе USDS хранятся в бинарном виде (не как текст).

Допустим, мы задокументировали этот формат и создали первую версию библиотеки для работы с ним. Есть ли профит? Бенчмарк расставит все по своим местам:

image

image

Что-то в этом уже есть, хотя работы еще не мало: Basic Parser всегда будет уступать Google Protobuf, но не на столько же.

Пример использования


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

Шаг 1: составляем Словарь


Как было сказано выше, документ USDS строится только по схеме, которая может выглядеть так:

USDS DICTIONARY ID=1000000 v.1.0
{
    1: STRUCT internalObject
    {
        1: UNSIGNED VARINT varintField;
            1: UNSIGNED VARINT varintField;
            2: DOUBLE doubleField;
            3: STRING<UTF-8> stringField;
            4: BOOLEAN booleanField;
        } RESTRICT {notRoot;}

        2: STRUCT rootObject
        {
            1: INT intField;
            2: LONG longField;
            3: ARRAY<internalObject> arrayField;
        }
}

Все правила построения схемы можно посмотреть здесь. Библиотека USDS Basic Parser пока что поддерживает далеко не все элементы схемы, но пример выше — рабочий. Сохраняем схему в текстовый файл, или вставляем прямо в исходный код, что дальше?

Шаг 2: инициализируем парсер:


Так или иначе, схема данных оказалась в массиве «text_dictionary», скормим его парсеру:

BasicParser* clientParser = new BasicParser();
clientParser->addDictionaryFromText(text_dictionary, strlen(text_dictionary), USDS_UTF8);

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

Шаг 3: создаем бинарный документ:


Алгоритм ничем не отличается от работы с любым другим DOM-парсером: добавляем несколько корневых объектов, инициализируем их значениями, генерируем выходной массив данных.

UsdsStruct* tag = clientParser->addStructTag("rootObject");
tag->setFieldValue("intField", 1234);
tag->setFieldValue("longField", 5000000000);
...
BinaryOutput* usds_binary_doc = new BinaryOutput();
clientParser->encode(usds_binary_doc, true, true, true);

const unsigned char* binary_data = usds_binary_doc->getBinary();
size_t binary_size = usds_binary_doc->getSize(); 

Особенности работы с массивами опущены, вы можете посмотреть их отдельно, скачав исходный код примера.

Шаг 4: декодирование бинарного документа:


Для чистоты эксперимента создадим отдельный объект парсера, не будем его инициализировать словарем и посмотрим, разберет ли он наш бинарный документ:

BasicParser* serverParser = new BasicParser();
serverParser->decode(binary_data, binary_size);

int int_value = 0;
long long long_value = 0;
tag->getFieldValue("intField", &int_value);
std::cout << "\tintField = " << int_value << "\n";
tag->getFieldValue("longField", &long_value);
std::cout << "\tlongField = " << long_value << "\n";

Обратите внимание, что «Сервер» заранее ничего не знает о схеме данных, но спокойно получил бинарник, нашел в нем поля по их текстовым именам и корректно преобразовал их в значения переменных С++. Именно эта функция недоступна в Google Protobuf и ASN.1.

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

Человекочитаемость


Это действительно очень важная функция: вы не можете прочитать посторонний бинарный пакет Google Protobuf или ASN.1 (кроме XER), а иногда очень хочется. При использовании BSON можно преобразовать любой пакет данных в JSON, что уже неплохо. Не отстает от него и USDS:

std::string json;
serverParser->getJSON(USDS_UTF8, &json);
std::cout << "JSON:\n" << json << "\n";

Сервер не только получил произвольный бинарный документ, но и смог преобразовать его в JSON. Ту же операцию можно было выполнить и на стороне «Клиента»: сформировать DOM-объект и сразу преобразовать его в JSON, который также строго соответствует схеме данных.

В планы разработки USDS заложен редактор документов USDS с полноценным GUI. В ближайшем будущем в USDS Basic Parser будет реализована конвертация между XML, JSON и USDS в любом направлении.

Заключение


Зачем я опубликовал сырой продукт (Pre-Alpha), который настоятельно не рекомендуется использовать в проектах? Мне важен ваш отклик:

  • чего не хватает в продукте?
  • нужен ли он вообще?
  • понятно ли написана документация и исходный код?
Отвечу в комментариях на любые вопросы.

Источники:

Страница проекта: USDS 1.0
Скачать библиотеку и исходный код примера можно здесь.
Исходный код библиотеки доступен здесь.

Комментарии (97)


  1. HDDimon
    09.11.2015 11:49
    +11

    А в чем коренные отличия от protobuf?


    1. NeoCode
      09.11.2015 11:56
      +1

      Присоединяюсь к вопросу. И в чем в protobuf вам не хватает функциональности?


    1. Zashibis
      09.11.2015 11:59
      +2

      Во-первых, сам бинарный формат немного отличается:

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

      Во-вторых, софт чуть другой, у protobuf есть только генератор парсеров. У USDS дополнительно предусмотрена бибилотека Basic Parser, которой можно скормить текстовое или бинарное описание словарей. Basic Parser всегда будет медленнее, чем сгенерированные парсеры, но она будет полезна для многих решений.


      1. HDDimon
        09.11.2015 12:10
        +2

        1. В чем приемущество?
        2. тип данных только в тэге? на сколько это быстрее/медленее protobuf?
        3. в protobuf есть возможно указать версию самого protobuf 2/3 или расширить схему версией. Тем более если вы расширяете схему, то сервер продолжит работать по старой схеме, то есть обратная совместимость сохраняется
        4. в protobuf есть возможность формирования dynamic message — это когда схема на стороне сервера может изменяться. То есть первым сообщением сервер вам отдает динамическую схему. на основании данной схемы вы создаете файловый дескриптор из которого может вытащить дескрипторы полей для декодирования бинарных данных.


        1. Zashibis
          09.11.2015 12:34

          1a. Предполождим вам пришло сообщение в формате protobuf: какое именно там сообщение? У протобуфа нет идентификаторов сообщений. Какая версия протокола у клиента? Протобуф вам это также не сообщит. в USDS вся эта информация есть в первых 10 байтах.
          1b. У вас есть файл, внутри которого protobuf: вы не можете открыть его редактором с GUI и внести правки, вы не можете сконвертировать его в XML или JSON (хотя может быть вы скомпилировали редактор и конвертор под свою схему данных, но это мало эффективно). В USDS эта проблема решена.

          2. Тег может иметь тип данных «структура», в этом случае указываются типы для полей. Быстрее/медленнее смотрите в статье, бенчмарк реальный приведен.

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

          4. Можно ссылку на это?


          1. HDDimon
            09.11.2015 12:51
            +1

            В официальных доках я этой информации не встречал, но может посмотреть на этот снипет

            Спасибо за ответы.


            1. Zashibis
              09.11.2015 13:21

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


              1. HDDimon
                09.11.2015 13:35

                мы активно используем динамические схемы protobuf в текущем проекте. Очень удобно получается.


  1. OldFisher
    09.11.2015 12:10
    +2

    Возможно, стоит добавить к сравнению CBOR?


    1. Zashibis
      09.11.2015 12:36

      Судя по структуре, его производительность на уровне BSON. Такие форматы всегда медленнее, чем protobuf или ASN.1. Если будет время — добавлю в бенчмарк.


  1. TimsTims
    09.11.2015 12:56
    +9

    Ждем картинки про новый стандарт


    1. Zashibis
      09.11.2015 13:43

      Вам какие именно картинки нужны?


      1. vlivyur
        09.11.2015 13:46
        +14


        1. Zashibis
          09.11.2015 13:48

          Есть 14 моделей жигулей. Зачем создавать новые модели, когда и существующие ездят?


          1. FractalizeR
            09.11.2015 14:48
            +1

            Для того, чтобы удовлетворить эго покупателя, который жаждет всего самого передового, например. Я думаю, при принятии решения о покупке «новой модели Х» это, часто, самый главный аргумент.

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


            1. Zashibis
              09.11.2015 15:14

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


              1. FractalizeR
                09.11.2015 15:31
                +10

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

                Не подумайте, что я не уважаю ваше начинание. То, что вы придумали новый формат и инструменты для него — замечательно. Однако…

                В чем прелесть XML? Он реализован под все платформы, «человекочитаемый», для него созданы схемы данных (условно человекочитаемые)

                Вам не удалось ни одной прелести XML повторить в вашей работе, не так ли? И у меня возникает вопрос, не произошла ли подмена тезиса? Вы собирались создать альтернативу XML, а получился конкурент для protobuf, messagepack и их друзей.

                Ведь XML — это не только XML, как формат передачи данных. Это еще и XML Schema, DTD и куча сопутствующих технологий. Я не уверен, что у вас получился конкурент существующему стеку.

                Человекочитаемость запланирована через Редактор, с GUI, без предварительного обучения, а не через «парсер»

                Человекочитаемость протокола — это возможность его чтения человеком из сырого вида, без предварительного преобразования. Например, HTTP 1.x — в основном человекочитаемый. А вот HTTP 2.x — уже нет, поскольку он бинарный. И если у меня есть WireShark, это все равно не означает, что HTTP 2.x стал для меня человекочитаемым.


          1. bromzh
            09.11.2015 15:46
            +1

            Плохой пример. Модели авто — это как версии софта. Есть несколько видов кузова (хэчбек/седан/универсал — это lite/standart/ultimate в софте). Но обычно каждые n лет эти модели обновляются и становятся лучше (для софта — это мажорный релиз). У кого есть средства для покупки авто/софта — те обновляются. Остальные остаются на старом.

            А стандарты — это как запчасти. Если бы они все были более-менее стандартными, то всё было бы легче. Однако в жизни запчасть от одной марки не подходит для другой. Например, у некоторых машин колесо крепится на 4 болта, у некоторых на 5, у некоторых на 6. Было бы намного легче, если бы стандарт был 1, тогда бы было проще заменять колёса. А новый стандарт выглядит как попытка какого-нибудь производителя навязать свою точку зрения, что колесо с 8 болтами уж точно станет стандартом. При этом, большинство машин не приспособлены для таких колёс. Да и готовые колёса не подойдут к машине с 8-ю креплениями.

            Текущие форматы справляются со своими задачами, зачем плодить новые сущности?


            1. Zashibis
              09.11.2015 16:01

              Все очевидно, новые форматы справляются с теми же задачами лучше (или умирают), даже JSON зачем-то сделали, хотя уже был XML.


              1. bromzh
                09.11.2015 16:50
                +2

                JSON взлетел, потому что парсер js есть в каждом браузере. Так что на стороне фронтенда он автоматом поддерживается. Как и xml.

                А парсер нового формата нужно как минимум внедрить во все браузеры. Включить парсер для нового неизвестного формата в стандарт ES никто не согласится. Загружать же библиотеку, чтобы прочитать данные многим будет влом, так как есть уже готовые json и xml + gzip, чего хватает с головой.


  1. lair
    09.11.2015 13:41
    +10

    бинарный формат, способный полностью заменить XML и JSON

    Нельзя, просто нельзя сравнивать бинарные форматы и текстовые. У них и задачи разные, и, как следствие, характеристики.

    И нет, вы не можете заменить json, потому что основное преимущество json — дешевый парсинг в браузере.

    И человекочитаемости у вас потому же нет, потому что человекочитаемость через специально обученный парсер — это неудобно, особенно когда ты пытаешься на лету понять, что происходит. А если документ некорректный, что тогда скажет парсер?


    1. Zashibis
      09.11.2015 13:47
      -10

      Добрый день!
      Если формат станет популярным, то его обязательно встроят в браузеры, я буду работать в этом направлении. И как у любого бинарного формата — его парсинг будет дешевле, чем JSON.
      Человекочитаемость запланирована через Редактор, с GUI, без предварительного обучения, а не через «парсер». И да, вы выдающая личность, если загружаете JSON из сетевог кабеля непосредственно в мозг :)
      Если документ некорректный, парсер выдаст вам ту часть, что смог распарсить, и объяснит на каком месте он запнулся. Мало чем отличается от анализа битых JSON и XML.


      1. lair
        09.11.2015 13:53
        +12

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

        В существующие на данный момент — тоже?

        Человекочитаемость запланирована через Редактор,

        Это не человекочитаемость.

        И да, вы выдающая личность, если загружаете JSON из сетевог кабеля непосредственно в мозг :)

        Да нет, я беру любой http-сниффер, и дальше могу свободно читать и писать.

        Мало чем отличается от анализа битых JSON и XML.

        Битые JSON и XML я могу открыть в произвольном текстовом редакторе и разбираться, что случилось. С бинарным файлом это сложнее на порядок.


        1. Zashibis
          09.11.2015 15:16
          -4

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


          1. lair
            09.11.2015 15:21
            +3

            Подсветку синтаксиса JSON там тоже не сразу реализовали.

            Речь не про подсветку синтаксиса, а про поддержку в JS.

            Снифферы трафика умеют отображать огромное количество бинарных форматов

            Я вот что-то не уверен в этом заявлении относительно, скажем, фиддлера. Скажем, поддержки protobuf я там не нашел (хотя, возможно, плохо искал).

            Вы открываете JSON и XML в редкторе, который скачали и установили себе на компьютер (стандартный блокнот разумеется не подходит).

            … и в стандартном блокноте тоже. Понятно, что на своем рабочем компьютере я пользуюсь для этих целей другим ПО, но я знаю, что я могу это сделать на любом компьютере, где есть хотя бы какой-нибудь текстовый редактор.

            Значит для вас не будет проблемой скачать и установить редактор для USDS.

            Я не хочу ставить еще один редактор.


            1. Zashibis
              09.11.2015 15:25

              Проблема protobuf в том, что его невозможно распарсить, не имея специально скомпилированного парсера, именно поэтому вы и не нашли его. В USDS эта проблема решена, если вы читали статью — то знаете как.
              Если вы скачаете для работы пакет библиотек USDS, то там же получите и редактор, я об этом позабочусь :)


              1. lair
                09.11.2015 15:27
                +1

                Если вы скачаете для работы пакет библиотек USDS, то там же получите и редактор, я об этом позабочусь

                Спасибо, я против. Мне еще лишнего софта не хватало, особенно учитывая, что «пакет библиотек» я планирую ставить нюгетом.


              1. HDDimon
                09.11.2015 15:38
                +1

                >> не имея специально скомпилированного парсера
                выше я описал что это неверно. парсер можно собирать на лету.


                1. Zashibis
                  09.11.2015 15:44

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


      1. vedenin1980
        09.11.2015 14:38

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

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

        И как у любого бинарного формата — его парсинг будет дешевле, чем JSON

        Время парсинг мало когда играет роль, JSON хорошо сжимается браузерными компрессорами/архиваторами, даже при чтении с диска чаще ДЕШЕВЛЕ разархивировать архивированный файл на лету и парсить в памяти, чем читать не архивированный файл с диска. Для чтения из сети вообще время парсинга редко критично, узким горлышком как правило будет получение данных, а не параллельный парсинг в памяти. Бинарный формат хорош для сериализации/десериализации объектов на диск, для записи в базу данных, но универсальность и стандартность для всех языков и платформ нафиг не нужна в большинстве случаев, все равно сериализированный объект Java не откроется в Net, но так как с большой вероятностью будет передача через сеть в архивированном виде, JSON прекрасно тут работает.


        1. Zashibis
          09.11.2015 15:19

          В описанном вами замкнутом круге всегда появляются исключения, некоторые вещи выстреливают. Оставим же шанс USDS :)
          Время парсинга на стороне браузера действительно роли не играет, вы распарсите JSON за 0.1 секунду, а USDS за 0.01с, а потом скрипт будет выполняться 2 секунды — кого вообще волнует парсинг?
          Зато ваш сервер сможет обслуживать в несколько раз больше пользователей, потому что на формирование миллиона JSON он потратит 10 секунд, а на тот же миллион USDS он потратит 1 секунду.


          1. vedenin1980
            09.11.2015 16:04

            Не сможет, потому что обслужить миллион запросов в секунду он не сможет просто потому что у него не хватит портов, не говоря уже о затратах на поддержание каналов и передачу данных. Если данные статические и сервер не лазиет в базу данных, файлы и т.п., то никто не мешает заранее закешировать JSON'ы популярных ответов, если сервер берет данные из базы данных, то время формирования JSON'ов вообще никакой роли не играет.

            Учитывая кеширование популярных запросов на стороне сервера, обращение к базе данных для получения данных и поддержку сетевых соединения, время на формирование JSON'a в 99.9% случаев значения не имеет. Тем более по своему опыту миллион JSON'ов нормальный сервер с быстрой JSON библиотекой сформирует намного быстрее чем за 1 секунду. Та же монга работает с бинарным JSON'ом и в целом сохраняет миллионы JSON объектов в секунду не особо напрягаясь и не считая поддержки соединений, индексов и запросов.


          1. vedenin1980
            09.11.2015 16:57
            +1

            Зато ваш сервер сможет обслуживать в несколько раз больше пользователей

            Простите, но вы понимаете что бинарные и текстовые протоколы существуют уже лет 50 и над ними работали миллионы инженеров (в том числе и над вопросами где использовать текстовый и где использовать бинарный протокол)? Вы правда верите, что если бы это было правдой кто-то сейчас использовал бы json, html или xml вместо бинарных протоколов (при том что когда появился html, xml и json сервера были в десятки или сотни раз слабее)? То есть вы уверены, что идея «а давайте вместе текстового протокола используем бинарный» настолько уникальна и никому не приходила в голову, что вы с ней захватите мир?


            1. Zashibis
              09.11.2015 17:21
              -5

              Да, я часто вижу, как используют текстовые форматы там, где просятся бинарные. Я вижу почему так делают — существующие бинарные форматы в большинстве своем ущербны, либо в их разработку вложили недостаточно ресурсов. В этих комментариях привели несколько реализаций бинарных форматов, но они не выстрелили и я вижу основные блокеры. Сложно сказать, чем занимались «миллионы» инжинеров последние 50 лет, если мы до сих пор используем текстовые форматы.


  1. novar
    09.11.2015 13:58
    +5

    А ещё есть EBML, «при создании которого стояла задача создать аналог XML для двоичных данных». EBML мы встречаем повсеместно в виде MKV-файлов.


    1. Zashibis
      09.11.2015 15:08

      По вашей же ссылке: «Очень важной особенностью формата является наличие «значений по умолчанию» для многих элементов»
      Эта особенность есть и у protobuf, и у USDS. Даже в XSD можно объявить опциональные поля, что сократит размер документов.


      1. TimsTims
        09.11.2015 16:48
        +3

        Тогда чем USDS лучше и зачем нужен еще один «стандарт» который захватит мир?


        1. Zashibis
          09.11.2015 16:57

          Он значительно быстрее текстовых форматов, компактнее и немного быстрее BSON и всех его клонов (в том числе EBML), и превосходит по функциональности «самые бинарные» protobuf и ASN.1. Я провел анализ большинства существующих форматов, прежде чем изобретать очередной велосипед и взял лучшие моменты от каждого, плюс предложил некоторые новшества.


          1. grossws
            10.11.2015 00:05
            +1

            компактнее и немного быстрее BSON
            В случае BSON и не гнались за компактностью. Он появился в рамках mongodb и возможность in-place update была куда важнее, чем компактность.


  1. OlegMax
    09.11.2015 16:53
    +1

    Вот уже люди задумались и даже предложили Efficient XML Interchange (EXI) Format.


    1. Zashibis
      09.11.2015 17:07

      С ходу не совсем понял этот инструмент, у вас есть опыт его использования? Это некий быстрый парсер для XML?


      1. OlegMax
        09.11.2015 17:11

        Это формат, а не парсер. Решает те же задачи, которые решали вы.


    1. FractalizeR
      09.11.2015 18:17
      +2

      А еще есть en.wikipedia.org/wiki/Fast_Infoset для XML ;)


  1. boolivar
    09.11.2015 19:46

    Была уже подобная разработка: habrahabr.ru/post/248147


    1. Zashibis
      10.11.2015 09:20
      +1

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


  1. mickvav
    09.11.2015 20:50
    -2

    SNMP?


  1. markhor
    09.11.2015 21:10
    +1

    Мда, вспомнилось, чем отличается обсуждение нового проекта на западной площадке и на российской. Англосакс: «Wow! It can be useful to me.» Русский: «Да нафига ты это написал, это никому не надо и т.п.»
    Жалко что-ли? :) Я к примеру тоже ощутил ущербность protobuf и согласен с автором. Даже если этот формат не выстрелит — заманчиво применить его у себя в специфических нишах, где он реально судя по тестам может дать профит. Собственно, именно по этой причине я вижу автор его и написал.
    У меня такой вопрос, под Linux работает? Python обертку хочется, чтобы поиграться с внутренностями. Я даже готов ее сам создать, благо опыт богатый в этом.


    1. markhor
      09.11.2015 21:49

      Вспомнил недавнюю статью на эту тему…


    1. Zashibis
      10.11.2015 09:24

      Да, когда я публиковал описание формата на англоязычных ресурсах, люди реагировали чуть добрее.
      Для Linux сейчас не получится скомпилировать, в одном классе присутствует виндовая «MultiByteToWideChar», но планируется ее вырезать (UTF-8 в UTF-16 можно и без нее сконвертировать). Я вам отправлю сообщение в личку, когда поправлю, но ждите не раньше нового года.


  1. dtestyk
    09.11.2015 21:30

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

    некоторые примеры:
    image
    называется CLS(Contexted Lists and Sets)


    1. Zashibis
      10.11.2015 09:25

      Вы правда считаете ваш пример «человекочитаемым»? Данный «убийца» вымрет не родившись.


      1. dtestyk
        10.11.2015 10:51

        Несомненно, но поскольку это довольно субъективно, решил отложить идею.
        А почему вы не считаете его человекочитаемым?

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


        1. Zashibis
          10.11.2015 11:06

          Согласен, «читаемость» субъективна. Что касается вашего примера и моего мнения: когда я впервые увидел JSON, я понял его сразу (имея опыт с XML), не обращаясь к документации (но читал документацию, чтобы писать собственные JSON).
          Глядя на ваш формат я затрудняюсь разобрать примерно 30% кода. Также есть сомнения, что он компактнее JSON, количество спецсимволов примерно такое же.


  1. grossws
    09.11.2015 23:43

    Что-то вспомнился старый добрый ASN.1 в представлении DER.


    1. grossws
      09.11.2015 23:45
      +2

      Увидел, что в таблицах бенчмарков есть ASN.1, но почему-то нет нормального бинарного DER. Как-то странно, что самого популярного и вполне быстрого варианта просто нет…


      1. Zashibis
        10.11.2015 09:28

        Да, к большому моему сожалению библиотека OSS, которую я использовал для тестирования ASN.1, падала при попытке работы с DER, поэтому он не был включен в бенчмарк.
        Сама по себе OSS не показатель производительности ASN.1, она уж больно медленная. Ребята, которые ее писали, очень любят деньги, и похоже периодически проверяют наличие лицензии на вашем ПК.


  1. JC_Piligrim
    10.11.2015 01:36
    +4

    А чем плох Apache Thrift для этих целей?

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


    1. Zashibis
      10.11.2015 09:31
      -2

      Apache Thrift — это скорее генератор API. Вы, конечно, можете прокидывать его пакеты через HTTP, но уж больно геморойно это будет.
      Второй недостаток — тот же что и у Protobuf и ASN.1: имея бинарный пакет вы не можете его «просмотреть по-человечески» без специально скомпилированного парсера.


      1. jrip
        10.11.2015 14:41
        +2

        Вы похоже вообще не понимаете что такое Apache Thrift и видимо поэтому написали какую-то полную фигню.
        >Apache Thrift — это скорее генератор API
        Это вообще что значит?
        Вообще, в нем есть либы для большинства популярных языков, а также генератор кода реализации конкретной версии протокола, который задается через специальный язык структур.
        >Вы, конечно, можете прокидывать его пакеты через HTTP, но уж больно геморойно это будет.
        В стандартных либах для большинства языков есть реализация для того чтобы «не геморойно» «прокидывать» через HTTP
        А также есть и бинарный транспорт, а еще можно и свой сверху нафигачить, какой захочется.
        >Второй недостаток
        Да вот нифига, в небинарной версии там json, немного привыкнув можно сразу понимать что происходит.
        И чего вы ставите в недостаток то, что в вашем протоколе как бы как минус также есть?


  1. ionsphere
    10.11.2015 08:26
    +2

    Или такой вариант github.com/Microsoft/bond?


    1. Zashibis
      10.11.2015 09:36
      -1

      Это еще один клон Apache Thrift, Protobuf и ASN.1, о чем они прямо и говорят на своем сайте. USDS принципиально отличается от них тем, что вы можете опционально поместить схему прямо в бинарный документ.


      1. lair
        10.11.2015 11:43
        +3

        Вообще-то, в бонде вы это тоже можете. Более того, в нем есть tagged-протоколы, где документ самоописан.


        1. Zashibis
          10.11.2015 12:37

          Смотрю ссылку. Подскажите, они умеют смешивать схему с данными, или посылать схему отдельно по запросу? Из докмента это не совсем понятно.


          1. lair
            10.11.2015 12:40
            +2

            (а) у них есть tagged-протокол, при котором схема не нужна, документ самоописывается
            (б) в случае untagged-протоколов для десериализации нужна схема. Эта схема точно так же может быть сохранена в и получена из бинарного потока (еще она может быть получена из самого класса, кстати). Дальше вы можете делать с ней что угодно: класть в поток перед документом, хранить в БД, передавать отдельным запросом — что хотите.


            1. Zashibis
              10.11.2015 12:42
              -1

              (а) tagged-протоколы мало кому интересны, они медленные, большие, годятся только для отладки. Моя библиотека тоже умеет генерить JSON для отладки.
              (б) Что подразумевается под «потоком»? Я хочу сохранить бинарный докумнет на диск в один файл, в нем будут и данные и схема, и это потом распарсится?


              1. lair
                10.11.2015 13:40
                +1

                tagged-протоколы мало кому интересны, они медленные, большие, годятся только для отладки.

                Видимо, MS так не считает: два их протокола (CompactBinary и FastBinary) — tagged.

                Я хочу сохранить бинарный докумнет на диск в один файл, в нем будут и данные и схема,

                Не надо мыслить «файлами», мыслите бинарными потоками. Сначала кладете схему, потом кладете данные. Когда читаете — в обратном порядке.


                1. Zashibis
                  10.11.2015 13:53

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


                  1. lair
                    10.11.2015 13:54

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


                    1. Zashibis
                      10.11.2015 14:03

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


                      1. lair
                        10.11.2015 14:06

                        В USDS второй стороне будет проще, т.к. парсер сам найдет схему данных в бинарном докуенте (при условии что ее туда вообще положили).

                        Вопрос в том, каков процент таких ситуаций, чтобы оправдать использование USDS вместо bond.


                        1. Zashibis
                          10.11.2015 14:13

                          Отслеживание трафика профайлером, редактирование конфигов в формате USDS, СУБД может передавать вам результаты SQL запросов в формате USDS: в начале документа схема, далее тонны данных (я плакал глядя на исходный код ODBC-драйвера).
                          У USDS есть и режим полной бинарности, когда вы не светите схему никому, и везде используются предварительно скомпилированные парсеры (как в protobuf, Bond и т.д.).


                          1. lair
                            10.11.2015 14:35

                            На вопрос «каков процент» это все не отвечает. Я искренне считаю, что в половине этих случаев tagged-протокол прекрасно устроит.

                            (а уж конфиги-то вообще не надо хранить в бинарном виде, зло это)


                            1. Zashibis
                              11.11.2015 14:04

                              Да ладно вам, вот конфиг в бинарном виде:
                              image


                              1. lair
                                11.11.2015 14:06
                                +8

                                Угу, без редактора — ни открыть, ни тем более поправить. Версионники передают привет. Инструменты трансформации и генерации — тоже передают привет.

                                Не, спасибо, не надо.


  1. kefirfromperm
    10.11.2015 09:14
    +4

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

    1. Схема +
    2. Человекочитаемость +-
    3. DOM +
    4. SAX — 5. StAX — 6. XPath — 7. XSLT -


    1. Zashibis
      10.11.2015 09:43

      SAX в USDS будет реализован очень не скоро, уж больно геморойная тема. Вы конечно можете взять классы InputBuffer/OutputBuffer из моего исходного кода, вооружиться документом «бинарная структура USDS» и писать значения из своих классов непосредственно в бинарный массив, но это прям сакс-хардкор будет.

      StAX — крутая штука, я уже думал о ней, надо реализовать обязательно, золотая середина между DOM и SAX.

      XPath и XSLT — в далеком светлом будущем, либо может найдуться активисты :)


  1. AllexIn
    10.11.2015 12:02
    +3

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

    Воспользуюсь я вашим форматом. Придет ко мне партнер и попросит подключить к моему каналу с данными…
    И чем это будет отличаться от подключения к самопальному бинарному контейнеру?


    1. Zashibis
      10.11.2015 12:39

      Тем, что вы дадите им ссылку на сайт продукта и предложите скачать библиотеку, которая не имеет внешних зависимостей и реализована под большинство языков (ах светлое будущее!).
      Таки ваш собственный «контейнер» с очень большой вероятностью будет завязан на внушительную часть вашего же исхдного кода.
      Взглянем на protobuf2: это изначально не было самостоятельным продуктом, его выделили. В результате для компиляции он тащит еще очень большой объем гугловых библиотек.


      1. AllexIn
        10.11.2015 12:50

        Парсер для любого(тем более бинарного) формата пишется за вечер.
        и я доверия испытываю больше к своему решению, чем к никому неизвестному формату.
        Сейчас можно продвинуть какой-то формат, если он будет реально революционные идеи в себе содержать. Ваш же формат, хоть и может быть удобен для каких-то задач, по факту ничего интересного, что заставило бы его использовать не несет.
        ИМХО с вероятностью 99.9 не взлетит.


        1. Zashibis
          10.11.2015 12:52
          -3

          Странно что я потратил на сырую пре-альфу два месяца. Наверное я что-то делаю не так :)


          1. AllexIn
            10.11.2015 12:55
            +1

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


            1. Zashibis
              10.11.2015 12:58
              -1

              Написать хороший парсер под свой собственный проект — две недели, плюс столько же на тестирование и неделя на документирование.


              1. AllexIn
                10.11.2015 13:31
                +2

                Хм. Скажем у меня есть сервис погоды и должен он отдавать погоду в определенных аэропортах.
                Как же будет выглядеть бинарный формат для этого дела?
                Наверное нам понадобится поддержка массивов, структур, строковых переменных и числ целых и с плавающей точкой.
                Как же в итоге будут выглядеть сами данные?
                Примерно вот так:

                int PackageSizePos = Package.WriteInt(PACKAGE_SIZE);//пишем сначала 0, а в конце построения перезаписываем размером всего пакета
                Package.WriteInt(PROTOCOL_VERSION); //ну чтобы не ломалось ничего при  смене версии
                Package.WriteInt(WEATHER_INFO); //WEATHER_INFO - константа, которая определяет тип содержимого
                Package.WriteInt(WEATHER_PROTOCOL_VERSION);
                Package.WriteString("SVO"); //Погода для аэропорта Шереметьево
                Package.WriteInt(Data.size()); //Количество периодов за которые есть информация
                for (unsigned int block = 0; block<Data.size(); block++){
                  Package.WriteDouble(Data[block].Date);//Дата и время на которое указана инфа
                  Package.WriteFloat(Data[block].Temperature);
                  Package.WriteFloat(Data[block].Humidity);
                  Package.WriteFloat(Data[block].WindDirection);
                  Package.WriteFloat(Data[block].WindSpeed);
                }
                Package.WriteInt(PackageSizePos,Package.size()+sizeof(int));//Пишем размер пакета + добавляем размер контрольки, которой еще нет
                Package.WrinteInt(CalcCRC(Package,Package.size()));//Пишем контрольную сумму в конце
                
                


                Хм. А как же все это будет читать партнер?
                Ну примерно так:
                if (Package.ReadInt()!=Package.size())
                	return ERROR_INCORRECT_PACKAGE;
                if (Package.ReadInt(Package.size()-sizeof(int))!=CalcCRC(Package,Package.size()-sizeof(int)))
                	return ERROR_INCORRECT_PACKAGE;
                if (Package.ReadInt()!=PROTOCOL_VERSION)
                	return ERROR_UNSUPPORTED_VERSION;
                switch(Package.ReadInt()){
                case WEATHER_INFO: return processWeatherPackage(Package);
                };
                return ERROR_UNSUPPORTED_PACKAGE_DATA;
                
                unsigned int processWeatherPackage(Package)
                {
                	if (Package.ReadInt()!=WEATHER_PROTOCOL_VERSION)
                		return ERROR_UNSUPPORTED_DATA_VERSION;
                	
                	std::string Code = Package.ReadString();
                	if (!checkCode(Code))
                		return ERROR_INCORRECT_PACKAGE;
                	unsigned int BlocksCount = Package.ReadInt();
                	if (BlocksCount>MAX_BLOCKS_COUNT)
                		return ERROR_INCORRECT_PACKAGE;
                	Ports[Code].resize(BlocksCount);
                	for (unsigned int block = 0; block<BlocksCount; block++){
                		Ports[Code].Data[block].Date = Package.ReadDouble();
                		Ports[Code].Data[block].Temperature = Package.ReadFloat();
                		Ports[Code].Data[block].Humidity = Package.ReadFloat();
                		Ports[Code].Data[block].WindDirection = Package.ReadFloat();
                		Ports[Code].Data[block].WindSpeed = Package.ReadFloat();
                	}
                	return OK;
                }
                
                

                Сколько я это писал? Минут 20. Задача совершенно с потолка, только сейчас ее придумал.
                Да, придется тестировать. Но все тестирование будет сводиться к проверке, что не валидные данные придти не могут. Неделя на тестирование? Пфф. Ерунда.
                Тем более что единственное что нужно будет, это перенести уже работающий код(ведь мы же делаем версию для платформы партнера, а не с нуля пишем). то есть по сути, написать методы чтения стандартных переменных. И всё. Все валидации будут уже в нашем коде и их надо буедт просто перенести.
                Что тут две недели писать?
                Для более сложных задач будет тоже самое. Я писал бинарный парсер для протокола, который имел 40(сорок) версий и нужно было не отваливаться на старой версии, а поддерживать их все. И даже для этого я писал код пару дней всего лишь.


                1. Zashibis
                  10.11.2015 14:00
                  -4

                  Только ваш C# потом не распарсится на Java, С++ и других языках, которые используются у партнеров.


                  1. AllexIn
                    10.11.2015 14:20
                    +2

                    Это еще почему?
                    Ну и это не шарп. :)


                    1. Zashibis
                      10.11.2015 14:36
                      -3

                      Возьмем вот этот метод:
                      Package.WriteString(«SVO»);
                      Это либо стандартная библиотека какого-то языка, что мешает парсить докумнет на других языках, либо ваша самописная, которая не входит в срок 1 вечер.


                      1. AllexIn
                        10.11.2015 14:47
                        +3

                        void cPackage::WriteString(const std::string& str )
                        {
                          WriteInt(str.size());
                          if (str.size()>0)
                            WriteRaw(str.c_str(),str.size());
                        }
                        
                        std::string cPackage::ReadString()
                        {
                          int Size = ReadInt();
                          std::string Result = "";
                          if (Size()>0){
                            Result.reserve(Size);
                            for (int i = 0; i<Size; i++)
                               Result+=ReadChar();
                          }
                          return Result;
                        }
                        

                        Уф. Минут пять писал.
                        А это, между прочим, самый сложный тип из всех.


                      1. AllexIn
                        10.11.2015 14:50
                        +1

                        которая не входит в срок 1 вечер.

                        А вообще, я про это и говорил:
                        «Тем более что единственное что нужно будет, это перенести уже работающий код(ведь мы же делаем версию для платформы партнера, а не с нуля пишем). то есть по сути, написать методы чтения стандартных переменных. И всё.
                        Весь вечер и будет состоять из времени потраченного на написания класса cPackage для нужной платформы. Причем, по факту, 90% этого вечера будет заниматься настройка девелоперского окружения. Ибо методы чтения и записи в поток для примитивных типов пишется за десятки минут. Если уже не написаны 1000 раз до этого.


                        1. Zashibis
                          10.11.2015 14:58
                          -1

                          У вас все еще нет обработки ошибок, юнит-тестов, работы с BigEndian.
                          А если вы возьмете тот же Protobuf, то все вопросы будут решены бустрее чем за 1 вечер.


                          1. AllexIn
                            10.11.2015 15:06
                            +3

                            У вас все еще нет обработки ошибок, юнит-тестов, работы с BigEndian.

                            А у вас? :)
                            У меня код написанный за 25 минут в общей сложности прямо в браузере. А у вас два месяца потрачено и где это всё? Тем же BigEndian в коде и не пахнет.
                            Разве что у вас обработка ошибок есть в зачаточном состоянии. Ну так и у меня базовая обработка ошибок сделана.

                            Давайте проще. Подождем и через два месяца посмотрим, что в вашем проекте изменится.


                            1. Zashibis
                              10.11.2015 15:10

                              Подпишитесь на меня тогда, я буду публиковать новости только по USDS и редко :)


                              1. AllexIn
                                10.11.2015 15:12
                                +2

                                Да я просто через пару месяцев приду да посмотрю, как оно чего. :)


  1. jrip
    10.11.2015 14:34
    +5

    Т.е. вы придумали некий очередной формат, сделали его реализацию только на с++ и громко заявили что это полоценная замена XML? :D


    1. Zashibis
      10.11.2015 14:36

      Я громко заявил, что выпустил Pre-Alpha.


      1. jrip
        10.11.2015 14:42
        +5

        Т.е. название статьи «Полноценная бинарная замена XML » это такой юмор?


        1. Zashibis
          10.11.2015 15:00
          -2

          Это такой формат. Вы ведь прочитали всю статью, и прекрасно поняли, что USDS действительно может заменить XML. Вы также прочитали цели публикации. Не пойму, причем здесь юмор?


          1. jrip
            10.11.2015 15:04
            +5

            Ну как бы прочитав статью, я как раз понял, что не сможет :)