Бинарное кодирование для соединений с низкой пропускной способностью? - PullRequest
1 голос
/ 30 ноября 2009

В моем приложении у меня есть простой файл в формате XML, содержащий структурированные данные. Каждая запись данных имеет тип данных и значение. Что-то вроде

<entry>
  <field type="integer">5265</field>
  <field type="float">34.23</field>
  <field type="string">Jorge</field>
</entry>

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

Проблема в том, что у нас соединение с очень низкой пропускной способностью (около 1000 бит / с, да, то есть бит в секунду), поэтому XML не совсем лучший формат для передачи данных. Я ищу способы кодировать XML-файл в двоичный эквивалент, который больше подходит для передачи.

Знаете ли вы какой-нибудь хороший учебник по этому вопросу?

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

Примечание. Это не преждевременная оптимизация, это обязательное условие. 1000 бит / с - это действительно низкая пропускная способность, поэтому считается каждый байт.

Примечание 2: Приложение написано на C #, но подойдет любой учебник.

Ответы [ 8 ]

2 голосов
/ 30 ноября 2009

Попробуйте использовать ASN.1 . Упакованные правила кодирования должны сами по себе создавать довольно прилично сжатую форму, а правила кодирования xml должны давать что-то эквивалентное существующему xml.

Также рассмотрите возможность использования 7zip вместо gzip.

1 голос
/ 30 декабря 2009

Поздний ответ - по крайней мере, до конца года; -)

Вы упомянули Fast Infoset. Вы пробовали это? Он должен дать вам наилучшие результаты с точки зрения компактности и производительности. Добавьте сжатие GZIP, и конечный размер будет очень маленьким, и вы избежите штрафов за обработку XML. WCF-Xtensions также предлагает кодирование сообщений Fast Infoset и сжатие GZIP / DEFLATE / LZMA / PPM (работает на .NET / CF / SL / Azure).

1 голос
/ 30 ноября 2009

Я бы хотел настроить ваше приложение так, чтобы оно реагировало на небольшие фрагменты XML; в частности те, которые достаточно малы, чтобы поместиться в один сетевой пакет.

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

1 голос
/ 30 ноября 2009

Первое, что нужно попробовать, это gzip; кроме того, я бы попробовал protobuf-net - я могу придумать несколько способов кодирования, которые достаточно легко, но это зависит от того, как вы создаете XML, и от того, хотите ли вы немного кода, чтобы подобрать эти два формата. В частности, я могу представить представление различных типов данных в виде или 3 необязательных полей одного и того же типа, или 3 различных подклассов абстрактного контракта.

[ProtoContract]
class EntryItem {
    [ProtoMember(1)]
    public int? Int32Value {get;set;}
    [ProtoMember(2)]
    public float? SingleValue {get;set;}
    [ProtoMember(3)]
    public string StringValue {get;set;}
}
[ProtoContract]
class Entry {
    [ProtoMember(1)]
    public List<EntryItem> Items {get; set;}
}

С тестом:

[TestFixture]
public class TestEntries {
    [Test]
    public void ShowSize() {
        Entry e = new Entry {
            Items = new List<EntryItem>{
                new EntryItem { Int32Value = 5265},
                new EntryItem { SingleValue = 34.23F },
                new EntryItem { StringValue = "Jorge" }
            }
        };
        var ms = new MemoryStream();
        Serializer.Serialize(ms, e);
        Console.WriteLine(ms.Length);
        Console.WriteLine(BitConverter.ToString(ms.ToArray()));
    }
}

Результаты (21 байт)

0A-03-08-91-29-0A-05-15-85-EB-08-42-0A-07-1A-05-4A-6F-72-67-65
1 голос
/ 30 ноября 2009

Я бы сбросил (для передачи в любом случае вы могли бы деконструировать в отправителе и реконструировать в получателе, в Java вы могли бы использовать собственный Input / OutputStream для аккуратной работы) XML. Перейти двоичные с фиксированными полями - тип данных, длина, данные.

Скажите, если у вас 8 или меньше типов данных, закодируйте их в три бита. Тогда длина, например, как 8-битное значение (0..255).

Затем для каждого типа данных кодируйте по-разному.

  • Integer / Float: BCD - 4 бита на цифру, используйте 15 в качестве десятичной точки. Или только сами необработанные биты (могут потребоваться разные типы данных для 8-битного, 16-битного, 32-битного, 64-битного длинного, 32-битного с плавающей запятой, 64-битного двойного).
  • String - можете ли вы использовать 7-битный ASCII вместо 8? И т. Д. Все заглавные буквы + цифры и некоторые знаки препинания могут привести к сокращению до 6 бит на символ.

Возможно, вы захотите добавить к общему количеству полей для передачи префикс. И выполнить кодирование CRC или 8/10, если транспорт с потерями, но, надеюсь, это уже обработано системой.

Однако не стоит недооценивать, насколько хорошо XML-текст может быть сжат. Я бы, конечно, сделал несколько вычислений, чтобы проверить степень сжатия.

1 голос
/ 30 ноября 2009

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

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

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

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

1 голос
/ 30 ноября 2009

Возможно, вы захотите изучить Буферы протокола Google . Они производят гораздо меньшую полезную нагрузку, чем XML, хотя не обязательно наименьшую возможную нагрузку; приемлемы ли они для вашего использования, зависит от многих факторов. Они, конечно, проще, чем разработать собственную схему с нуля.

Они были портированы на C # /. NET и, по-моему, работают довольно хорошо в моем (пока что несколько ограниченном) опыте. По этой ссылке есть пакет для некоторой интеграции с VS и автоматического создания классов C # из файлов .proto, что очень хорошо.

0 голосов
/ 30 ноября 2009

Вот рассол, в котором вы находитесь: вы сжимаете вещи с помощью Gzip. Gzip ужасен для простого текста до тех пор, пока вы не достигнете длины общих сочинений Диккенса или около 1200 строк кода. Накладные расходы на словарь и другие вещи, которые Gzip использует для сжатия.

1 Кбит / с подходит для задания 7500 символов (при оптимальных условиях это займет около минуты, но для <300 символов все будет в порядке!) Однако, если вы действительно заинтересованы, вы собираетесь хочу сжать это для краткости. Вот как я делаю вещи такого масштаба: </p>

T[ype]L[ength][data data data]+

То есть, что T представляет ТИП. скажем, 0x01 для INT, 0x02 для STRING и т. д. LENGTH - это просто целое число ... поэтому 0xFF = 254 символа и т. д. Пример пакета данных будет выглядеть так:

0x01 0x01 0x3F 0x01 0x01 0x2D 0x02 0x06 H E L L O 0x00

Это говорит о том, что у меня есть INT, длина 1, значения 0x3F, INT, длина 1, значения 0x2D, ​​затем STRING, длина 6 с нулем в конце "HELLO" (предположил Ascii). Узнайте о чудесах System.Text.Encoding.Utf8.getBytes, BitConverter и ByteConverter.

для справки см. Эта страница , чтобы узнать, сколько составляет 1 Кбит / с. Действительно, для размера, с которым вы имеете дело, все должно быть в порядке.

...