Эффективная упаковка данных для клиент-серверной сети

8

Язык: C ++

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

Для менее зависящих от производительности систем я просто отправлял бы строки, которые разделялись бы пробелом, являясь данными «действия» и первым «словом» идентификатора пакета, и просто цепочкой, если операторы проверяли наличие совпадений ,

Теперь для более критической системы, то, что я до сих пор думал, было что-то вроде этого:

Создайте строку с идентификатором пакета и данными и отправьте ее. Затем, чтобы распаковать, я мог бы извлечь первое целое число в строке и, имея массив обработчиков пакетов, с индексами, соответствующими идентификатору пакета, который они обрабатывают, и просто сделать что-то вроде packetHandlers [packetID] .Process (packetData).

Что вы думаете об этом, какие-либо предложения? высоко ценится!

Гримшоу
источник

Ответы:

10

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

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

  • (обновление) Первоначальный разработчик Protocol Buffers (v2) разработал новый протокол под названием Cap'n Proto. Он объясняет свои дизайнерские решения и сравнивает с другими аналогичными библиотеками, которые были недавно выпущены: Cap'n Proto, FlatBuffers и SBE .
  • Основным узким местом Google является сетевое взаимодействие между компьютерами, поэтому они, вероятно, учитывали эффективность при разработке буферов протокола . Изящно обрабатывает прямую / обратную совместимость ( когда вы решаете изменить свои структуры данных). Используется всеми основными продуктами Google (Gmail, Поиск и т. Д.)
  • Apache Thrift - это аналогичный протокол, используемый Facebook.
  • RakNet - это сетевая библиотека с открытым исходным кодом, специально разработанная для разработки игр.
  • ZoidCom - еще одна сетевая библиотека, ориентированная на разработку игр. Это не с открытым исходным кодом, но вы все еще можете изучить его для подсказок дизайна.

Первое правило оптимизации программы: не делайте этого.
Второе правило оптимизации программы (только для экспертов!): Пока не делайте этого.

[ Майкл А. Джексон ]

Другими словами: ваш основной параметр оптимизации должен быть: жизнь (годы жизни на реализацию программы). [ Как программировать независимые игры. Слайд 21. Джонатан Блоу. ]

Leftium
источник
1
приятный читатель! Большое спасибо за полный ответ, это, безусловно, помогло, и я полностью следую вашему совету, просто абстрагируйте это, сделав его пока достаточно простым :)
Grimshaw
Уверен, что сценарий использования Google для буферов протоколов не был эффективностью в стандартном смысле, но чтобы максимизировать совместимость между всеми возможными платформами и любыми будущими версиями данных (что является эффективностью в другом свете). Я буду здесь читать ваши другие заметки, очень хорошую коллекцию для меня, чтобы заново познакомиться с предметом.
Патрик Хьюз
RakNet не является открытым исходным кодом.
Герстманн
@Gerstmann: Raknet с открытым исходным кодом (еще раз): github.com/OculusVR/RakNet
Leftium
0

Зачем использовать две разные схемы кодирования? Просто используйте второй для каждой системы. Просто будь проще.
Рассмотрите возможность использования дельта-сжатия. Т.е. отправить одно полное значение и после этого только то, что изменилось. После нескольких итераций игры снова отправьте полную стоимость.
Еще одна кодировка, которую вы можете рассмотреть, - Base 128 Varint. Google Protobufs использует его. Взгляните на страницу «Кодировка» их руководства разработчика: Кодировка буферов протокола Может сэкономить несколько байтов.

Lurca
источник
Первая система, о которой я говорил, была просто примером из других проектов :) Мне, конечно, понравилась идея дельта-сжатия, спасибо, приятель!
Гримшоу
0

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

Таким образом , пакет , который состоит из четырех частей данных id, val1, val2и val2может выглядеть следующим образом :

// I'm using words (one byte) so my sample data is short
00000001 00101000 00010110 00010100 

Когда вы читаете первый байт (который, как вы знаете, всегда будет там), вы решаете, как обрабатывать следующий набор данных. Если первое слово (id) - это 00000001вы знаете, за ним следуют еще три слова, и это конец пакета. Продолжая пример, вы можете иметь идентификатор = 00000010и ваша спецификация говорит вам , что значение идентификатора 2, вы обрабатываете float, float, floatв таком порядке, который мог бы указать позицию игрока в мировом пространстве.

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

Nate
источник
Понятно, единственный вопрос, который у меня остается: достаточно ли упаковать все эти целые числа и числа с плавающей точкой в ​​стандартную строку или мне следует использовать более легкие типы данных?
Гримшоу
Как говорят другие, начните со строки и посмотрите, что произойдет. Скорее всего, у вас будет узкое место в другом месте вашего кода.
конец