Вопрос

Я разрабатываю игровой сервер и никогда раньше не делал ничего подобного.Мне просто интересно, какая хорошая структура пакета будет с точки зрения данных?Я использую TCP, если это имеет значение.Вот пример и то, что я собирался использовать на данный момент:

(каждое значение в скобках — это байт)

[Packet length][Action ID][Number of Parameters]
[Parameter 1 data length as int][Parameter 1 data type][Parameter 1 data (multi byte)]
[Parameter 2 data length as int][Parameter 2 data type][Parameter 2 data (multi byte)]
[Parameter n data length as int][Parameter n data type][Parameter n data (multi byte)]

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

Это было полезно?

Решение

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

В целом, я согласен с brazzy, механизм сериализации, предоставляемый языком, предпочтительнее любого самодельного.

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

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

Endiannes является важным фактором, особенно в C-подобных языках.Обязательно проясните, что пакеты всегда имеют один и тот же порядок байтов или что вы можете определить другой порядок байтов на основе подписи или чего-то еще.Странная вещь, которая очень классная:C# и .NET, кажется, всегда хранят данные в соглашении с прямым порядком байтов, когда вы получаете к ним доступ, как описано в этом посте здесь.Обнаружил это при портировании такого приложения на Mono на SUN.Круто, но если у вас есть такая настройка, вам в любом случае следует использовать средства сериализации C#.

В остальном ваша установка выглядит очень хорошо!

Другие советы

Начните с рассмотрения гораздо более простой базовой оболочки:Тег, длина, значение (TLV).Ваш базовый пакет будет выглядеть так:

[Tag] [Length] [Value]

Ярлык — это идентификатор пакета (например, идентификатор вашего действия).

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

Ценить содержит реальные данные.Формат этого может быть любым.

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

Как уже говорили другие, я бы поставил идентификатор пакета (тег) на первое место.Если у вас нет проблем с кросс-платформенностью, я бы рассмотрел возможность упаковки сериализованного объекта вашего приложения в TLV и отправки его по сети таким образом.Если вы допустили ошибку или захотите изменить позже, вы всегда можете создать новый тег с другой структурой.

Подробнее смотрите в Википедии TLV.

Чтобы не изобретать велосипед, любой протокол сериализации будет работать с проводными данными (например,XML, JSON), и вы можете рассмотреть возможность просмотра ЗВУКОВОЙ СИГНАЛ для базовой структуры протокола.

В документе часто задаваемых вопросов BEEP хорошо резюмируется следующим образом:своего рода альбом «лучших хитов» трюков, используемых опытными разработчиками протоколов приложений с начала 80-х годов.'

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

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

[action ID][item 1 (sizeof(item 1 bytes)][item 1 (sizeof(item 2 bytes)]...[item n (sizeof(item n bytes)]

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

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

--

Другой вариант — использовать « » для обозначения ваших переменных.Это потребует некоторых накладных расходов, и вам придется использовать текст, а не двоичные значения для чисел.Но таким образом вы можете просто использовать readline для чтения каждой переменной.Ваши пакеты будут выглядеть так

[action ID]
[item 1 (as text)]
...
[item n (as text)]

--

Наконец, простая сериализация объектов и передача их по сети — хороший способ сделать это с наименьшим количеством кода для написания.Помните, что вы не хотите преждевременно оптимизировать, в том числе и сетевой трафик.Если окажется, что вам нужно выжать немного больше производительности позже, вы можете вернуться и найти более эффективный механизм.

И проверьте Google буферы протокола, которые предположительно представляют собой чрезвычайно быстрый способ сериализации данных нейтральным для платформы способом, вроде двоичного XML, но без вложенных элементов.Есть также JSON, что является еще одной платформо-нейтральной кодировкой.Использование буферов протокола или JSON означает, что вам не придется беспокоиться о том, как именно кодировать сообщения.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top