Как дельта-кодировать структуру C / C ++ для передачи через сокеты - PullRequest
5 голосов
/ 24 октября 2009

Мне нужно отправить структуру C по проводам (используя UDP-сокеты и, возможно, XDR в какой-то момент) с довольно высокой частотой обновления, что потенциально может привести к большому количеству избыточного и ненужного трафика на нескольких килогерцах.

Это потому, что некоторые данные в структуре не могли изменяться время от времени, поэтому я подумал, что дельта-кодирование текущей структуры C относительно предыдущей структуры C может показаться хорошей идеей, во многом как "diff" ».

Но мне интересно, как лучше всего сделать что-то подобное, в идеале портативным способом, который также обеспечивает сохранение целостности данных? Можно ли будет просто XOR данных и действовать следующим образом?

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

Любые идеи или указатели (существуют ли библиотеки?) Будут высоко оценены!

Спасибо

РЕДАКТИРОВАТЬ: Спасибо всем, кто предоставил ответ, уровень детализации действительно ценится, я понимаю, что, вероятно, я не должен был упомянуть UDP, хотя, на самом деле это не главная проблема, потому что уже есть соответствующая Протокол, реализованный поверх UDP, который учитывает упомянутые трудности, поэтому на самом деле вопрос должен был быть специфичным для возможных средств дельта-кодирования структуры, а не столько об использовании UDP, в частности, в качестве транспортного механизма.

Ответы [ 4 ]

4 голосов
/ 24 октября 2009

UDP не гарантирует, что данный пакет был фактически получен, поэтому кодирование того, что вы передаете как «отличие от последнего времени», проблематично - вы не можете знать , что ваш коллега имеет ту же идею как вы о том, что "последний раз" был . По сути, вам придется создать некоторые накладные расходы поверх UDP, чтобы проверить, какие пакеты были получены (пометить каждый пакет уникальным идентификатором) - все, кто пытался пойти по этому пути, согласятся, что чаще всего вы обнаруживаете, что больше или меньше дублирования потоковой инфраструктуры TCP поверх UDP ... только, скорее всего, не так надежно и хорошо развито (хотя по общему признанию иногда вы можете воспользоваться очень особыми характеристиками ваших полезных нагрузок, чтобы получить некоторое скромное преимущество по сравнению с простым товаром) старый ПТС).

Ваша передача должна быть односторонней, от отправителя к получателю? Если это так (то есть, для получателя неприемлемо отправлять подтверждения или повторные передачи), то в действительности вы мало что можете сделать в этом направлении. Одна вещь, которая приходит на ум: если нормально, что получатель какое-то время не синхронизирован, отправитель может отправить два вида пакетов - один с полным изображением текущего значения структуры и идентифицирующим уникальный тег, отправляемый, по крайней мере, каждые (скажем) 5 минут (поэтому реально получатель может быть не синхронизирован до 15 минут, если пропустит два из этих «больших пакетов»); один только с обновлением (diff) последнего «большого пакета», включая идентификационный уникальный тег большого пакета и (например) версию XOR с кодированной длиной серии, о которой вы упомянули.

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

Необходимость управления версиями и c, в зависимости от того, что именно вы имеете в виду (будут ли отправители и получатели с различными идеями о том, как должен выглядеть макет структуры C структуры, регулярно общаться? Как они сообщают о том, какие версии известны обоим? И т. Д.) , добавит еще одну вселенную осложнений, но это действительно другой вопрос, и ваш основной вопрос, кратко изложенный в заголовке, уже достаточно большой; -).

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

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

3 голосов
/ 24 октября 2009

Для дельта-кодирования:

1) Периодически отправлять «ключевые кадры» (например, раз в секунду). Ключевой кадр - это полная копия (а не дельта), поэтому, если по какой-либо причине вы потеряете связь, вы потеряете лишь небольшое количество данных, прежде чем сможете снова «получить сигнал». Используйте простой заголовок пакета, который позволяет вам определить начало пакета и узнать, какой тип данных он содержит.

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

3) Добавить проверку CRC в пакет (поиск CRC32). Это позволит получателю удостовериться в том, что пакет был получен в целости и сохранности, и пропустить недопустимые пакеты.

ПРИМЕЧАНИЯ:

  • Будьте осторожны при выполнении этого через UDP - это не гарантирует, что ваши пакеты будут доставлены в том же порядке, в котором вы их отправили. Очевидно, что дельта будет работать, только если пакеты в порядке. В этом случае вам нужно будет добавить некоторую форму идентификатора последовательности к каждому пакету (первый пакет - «1», второй пакет - «2» и т. Д.), Чтобы вы могли обнаружить неупорядоченный прием. Возможно, вам даже понадобится сохранить буфер «n» пакетов в приемнике, чтобы вы могли собрать их в правильном порядке, когда придете их декодировать (но, конечно, это может привести к некоторой задержке). Вы, вероятно, также пропустите некоторые пакеты по UDP, и в этом случае вам придется подождать до следующего ключевого кадра, прежде чем вы сможете «повторно получить сигнал» - поэтому ключевые кадры должны быть достаточно частыми, чтобы избежать катастрофических сбоев в твоих комм.

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

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

1 голос
/ 24 октября 2009

Я не уверен, что значения дельта-кодирования в UDP - которые по своей природе ненадежны и вышли из строя - будут особенно простыми. Вместо этого я отправил бы идентификатор поля, которое изменилось, и его текущее значение. Это также не требует изменений, если вы хотите добавить дополнительные поля в структуру данных, которую вы отправляете. Если вы хотите стандартный способ сделать это, посмотрите на SNMP; это может быть что-то, что вы можете добавить, или это может быть немного мешающе для вас (это определяет глобальные имена полей и использует ASN.1 - оба из которых обеспечивают максимальную совместимость, но за счет некоторых байтов в пакете).

0 голосов
/ 24 октября 2009

Используйте RPC, такой как corba или буфер протокола

Использовать DTLS с опцией сжатия

Используйте упакованный формат

Повторно использует существующую библиотеку сжатия заголовков

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