Доступные языки определения сетевого протокола игры и генерация кода

Я искал хорошую универсальную структуру определения бинарного сетевого протокола, чтобы обеспечить возможность написания игровых серверов и клиентов в реальном времени (например, World Of Warcraft или Quake III) на нескольких языках (например, бэкэнд-сервер Java и интерфейс iPhone). клиент написан в Objective-C и Какао).

Я хочу поддерживать клиенты Java Flash, клиенты iPhone и клиенты C# в Windows (и клиенты XNA в XBOX).

Я ищу способ эффективно отправлять / получать сообщения через потоковое соединение сокетов TCP/IP или UDP. Я не ищу что-то, что можно отправить через HTTP-веб-сервис, например, JSON или XML-маршалы Objects. Хотя протокол двоичного веб-сервиса Гессиана является очень интересным решением

Мне нужен формат сетевого протокола и базовая реализация клиент / сервер, которая позволит клиенту подключаться к серверу и отправлять любое сообщение в определенном протоколе и получать любое сообщение в протоколе без необходимости привязки к какой-либо конечной точке RPC. Я хочу общий поток любого сообщения в моем протоколе входящих и исходящих. Это сделано для того, чтобы я мог поддерживать такие вещи, как сервер, отправляющий всем клиентам позиции различных объектов в игре каждые 100 миллисекунд.

9 ответов

Решение

Платформы сетевых протоколов, которые я обнаружил, следующие:

  1. Протокол Google Buffer - но в нем отсутствует поддержка таких вещей, как отправка / получение произвольных сообщений по вашему заданному протоколу.
  2. Apache Thrift - интересный вариант, но он ориентирован в основном на RPC, а не на общие игровые соединения типа клиент-серверный сокет, где клиент или сервер могут отправлять сообщения в любое время, а не только в ответ на запрос RPC клиента.
  3. Raknet Multiplayer - Raknet предоставляет полную многопользовательскую сетевую библиотеку (она бесплатна для инди-разработки с доходом менее $250 тыс.)

ОБНОВЛЕНИЕ: OculusVR приобрел RakNet и его Free/OpenSource сейчас. Вы можете найти его на Github

  1. Hessian Binary Web Service Protocol - это двоичный протокол веб-службы HTTP, он хорошо подходит для отправки двоичных данных без необходимости расширять протокол с помощью вложений.

Raknet предоставляет хорошую многопользовательскую библиотеку, ориентированную на игру / симуляцию.

Буферы протоколов Apache Thrift и Google, похоже, являются простейшими подходами к использованию в архитектуре клиент / сервер игрового сетевого протокола.

Похоже, Hessian отлично подходит, если вы хотите создать игровой сервер на основе веб-интерфейса с Java или флеш-клиентом с использованием некоторой технологии push-сервера, такой как COMET. Гессиан может предоставить действительно интересный способ поддержки игр в реальном времени в Интернете и даже иметь возможность размещать их в виртуальных веб-решениях, таких как Google App Engine или Amazon EC2.

Там обсуждается использование различных структур определения протокола для игр и других целей:

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

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

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

Распространенное решение этой проблемы в игровых компаниях состоит в том, чтобы иметь язык описания протокола или спецификацию в простом формате, таком как XML, python или lua, а затем иметь генерацию кода для каждого целевого языка, который генерировал классы пакетов как со структурой данных, так и с сериализацией. Эта спецификация может использовать систему типов, которая начинается с базовых типов, а затем распространяется на специфичные для игры типы с семантической информацией, перечислениями или более сложными структурами. Например, файл данных может выглядеть так:

Attack = {
  source = 'objectId',
  target = 'objectId',
  weapon = 'weapon::WEAP_MAIN',
  seed = 'int'
}

Это может генерировать код как:

#define PT_ATTACK 10002

class PacketAttack : public Packet {
  public:
    PacketAttack () : m_packetType(PacketAttack::s_packetType) {}

    ObjectId m_source;
    ObjectId m_target;
    WeaponType m_weapon;
    int m_seed;

   bool Write(Stream* outStream) {
       Packet::Write(outStream);
       outStream << m_source;
       outStream << m_target;
       outStream << m_weapon
       outStream << m_seed;
   }

   bool Read(Stream* inStream);

 static const int s_packetType;
};

Это требует больше инфраструктуры... потоков, базовых классов пакетов, функций безопасной сериализации.

Почему бы не реализовать UDP напрямую? В вашем вопросе в основном упоминается, что вы не хотите. Какую дополнительную форму абстракции вы хотите использовать поверх UDP? Загрузите исходный код Quake III и посмотрите, как они создают обновления игры по UDP?

Протокол IP был разработан для единой поддержки нескольких устройств / ОС, разве это не то, что вы просите? Какой протокол имеет реализации в огромном диапазоне систем, хм, IP, может быть?

Поскольку вы хотите использовать разные языки, а также потому, что вы хотите что-то чистое / маленькое, я предлагаю буферы протокола Google. Вам нужна прекомпиляционная часть для RPC, но я действительно считаю, что это лучший вариант, когда вы начинаете смешивать разные языки... Вот ссылка: http://code.google.com/apis/protocolbuffers/docs/overview.html

ASN.1 соответствует определению "хорошая структура определения бинарного сетевого протокола общего назначения". Он также стандартизирован МСЭ-Т, поэтому существует множество существующих инструментов и библиотек для различных языков.

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

Я хочу повторить предложение Билла К. Нетрудно накатить собственный протокол.

Что касается iPhone, взгляните на AsyncSocket, который поддерживает встроенные TCP-пакеты на основе разделителя, и нетрудно создать решение, которое использует заголовки пакетов.

Если вы быстро захотите, чтобы тестовый сервер играл с AsyncSocket на iPhone, вы можете взглянуть на Naga (для серверной части Java), который имеет готовые вещи как для пакетов на основе разделителя, так и для пакетов с заголовками. Нага был частично написан с учетом сетевых игр.

Я не согласен с "подходом с использованием простых строк с разделителями": вопрос в том, что именно принесет пользу? Начало писать и поддерживать больше кода? Единственные причины, которые я мог видеть, это отсутствие поддержки инструмента (запись для какой-то нечетной платформы), или конкретные (очень) жесткие ограничения производительности или размера сообщения. Или иногда очень хочется написать формат - это нормально, но это должно быть явной причиной.

В зависимости от конкретных потребностей я бы предложил рассмотреть JSON, поскольку он может читать и писать произвольные сообщения; имеет хорошие связыватели объектов для Java (так же, как xml), легче для чтения, чем двоичные форматы, и достаточно "хорош" для многих случаев использования.

Если размер сообщения очень важен, Protobuf может работать хорошо - хотя его размер не всегда такой же маленький, как у альтернатив gzip (gzip+xml, gzip+json сжимают очень хорошо), он обычно близок.

Другие вопросы по тегам