Доступные языки определения сетевого протокола игры и генерация кода
Я искал хорошую универсальную структуру определения бинарного сетевого протокола, чтобы обеспечить возможность написания игровых серверов и клиентов в реальном времени (например, 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 ответов
Платформы сетевых протоколов, которые я обнаружил, следующие:
- Протокол Google Buffer - но в нем отсутствует поддержка таких вещей, как отправка / получение произвольных сообщений по вашему заданному протоколу.
- Apache Thrift - интересный вариант, но он ориентирован в основном на RPC, а не на общие игровые соединения типа клиент-серверный сокет, где клиент или сервер могут отправлять сообщения в любое время, а не только в ответ на запрос RPC клиента.
- Raknet Multiplayer - Raknet предоставляет полную многопользовательскую сетевую библиотеку (она бесплатна для инди-разработки с доходом менее $250 тыс.)
ОБНОВЛЕНИЕ: OculusVR приобрел RakNet и его Free/OpenSource сейчас. Вы можете найти его на Github
- Hessian Binary Web Service Protocol - это двоичный протокол веб-службы HTTP, он хорошо подходит для отправки двоичных данных без необходимости расширять протокол с помощью вложений.
Raknet предоставляет хорошую многопользовательскую библиотеку, ориентированную на игру / симуляцию.
Буферы протоколов Apache Thrift и Google, похоже, являются простейшими подходами к использованию в архитектуре клиент / сервер игрового сетевого протокола.
Похоже, Hessian отлично подходит, если вы хотите создать игровой сервер на основе веб-интерфейса с Java или флеш-клиентом с использованием некоторой технологии push-сервера, такой как COMET. Гессиан может предоставить действительно интересный способ поддержки игр в реальном времени в Интернете и даже иметь возможность размещать их в виртуальных веб-решениях, таких как Google App Engine или Amazon EC2.
Там обсуждается использование различных структур определения протокола для игр и других целей:
- Сравнение различных рамок сериализации
- Thrift vs Protocol Buffers - Thrift объявлен лучшей платформой, поскольку имеет полностью поддерживаемую реализацию клиент / сервер RPC
- Использование буферов протокола для клиентского сервера Game API, определяющий тип сообщения для декодирования
- Двунаправленный RPC с использованием Thrift
Если вы идете по пути написания своего собственного протокола, вы можете прочитать ответ, который я разместил здесь.
В заключение, он обсуждает, что вы должны думать при написании протокола, и перечисляет несколько приемов для управления версиями и обеспечения обратной и прямой совместимости.
Если вы действительно беспокоитесь о множестве платформ и языков, обязательно учтите проблемы порядка байтов. Бинарный протокол, разработанный для этого использования, должен использовать сетевой порядок байтов, поэтому ему нужны настраиваемые функции сериализации для каждого типа данных; Вы не можете просто вслепую вставить структуры 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 сжимают очень хорошо), он обычно близок.