Какой протокол сокет-сервера эффективен? - PullRequest
1 голос
/ 04 мая 2010

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

1 = character starts turning right
2 = character starts turning left
3 = character stops turning
4 = character starts moving forward
5 = character stops moving
6 = character teleports to x, y

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

4
1

Или, чтобы телепортироваться на 100x200:

6#100#200

Где # - разделитель параметров.

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

Конечно, все данные будут проверяться на стороне сервера, но это другая тема.

Теперь, мне кажется, это достаточно эффективно, всего 2 байта, чтобы сообщить серверу, что я двигаюсь вперед и поворачиваю направо.

Однако большинство "профессиональных" фрагментов кода, которые я видел, казалось, отправляли объекты или команды xml. Мне кажется, это требует гораздо больше ресурсов сервера, не так ли?

Является ли моя неопытная логика того, почему мой текстовый протокол будет эффективен? Или какой протокол рекомендуется использовать для многопользовательских игр в реальном времени?

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

Ответы [ 4 ]

4 голосов
/ 05 мая 2010

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

Является ли моя неопытная логика того, почему мой текстовый протокол будет эффективным недостатки? Или что рекомендуется протокол для действий в реальном времени многопользовательские игры?

Обычный текст более дорогой для отправки, чем двоичный формат, содержащий ту же информацию. Например, если вы отправляете только 1 байт, вы можете отправить только 10 разных команд, цифры от 0 до 9. Бинарный формат может отправлять столько разных команд, сколько есть разных значений, которые можно вписать в байт, т.е. 256.

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

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

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

4 голосов
/ 04 мая 2010

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

Я не могу говорить по всем играм, но когда я работал над этим кодом, мы отправляли информацию об ориентации и положении по проводам. Таким образом, получатель может выполнять сглаживание и экстраполяцию (выяснить, где объект должен находиться «сейчас», основываясь на данных, которые у меня есть, которые уже известны как старые). Разные игры захотят отправлять разные данные, но, вообще говоря, вам нужно будет выяснить, как сделать так, чтобы отображение данных получателем соответствовало данным отправителя, поэтому вам нужно будет отправлять данные, которые устойчивы перед лицом сетевых проблем. 1003 *

Кроме того, многие игры используют UDP для передачи данных такого типа вместо TCP. UDP ненадежен, поэтому вы можете не получить все свои пакеты. Это означает, что «прекратить движение сейчас» или «начать движение сейчас» могут не приниматься парами. При кодировании поверх UDP тогда еще более важно посылать «это состояние сейчас» так часто, чтобы у клиентов была широкая возможность синхронизации.

3 голосов
/ 04 мая 2010

Обычный способ - использовать двоичный формат, а не текст, а не XML. Таким образом, только с одним байтом вы можете представить одну из 256 различных команд.

Также используйте UDP, а не TCP. Игра будет намного быстрее реагировать на UDP в случае потери пакетов. В случае потери пакета вы все равно можете экстраполировать движения. С каждым пакетом отправляйте номер пакета, чтобы сервер знал, когда была отправлена ​​команда.

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

редактирование:

Я почти забыл .. Протоколные буферы Google могут оказать большую помощь при отправке сложных структур данных.

1 голос
/ 21 июня 2011

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

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

В качестве примера приведем приблизительный код:

private const MOVE_RIGHT:int = 0; 
private const MOVE_LEFT:int = 1;
private const MOVE_UP:int = 2;
private const MOVE_DOWN:int = 3;

function processData(e:event.data)
{
    switch (e)
    {
       case MOVE_RIGHT:
       //move the clients player to the right

       case MOVE_LEFT:
       //move the clients player to the left

       case MOVE_UP:
       //move the clients player to the up

       case MOVE_DOWN:
       //move the clients player to the down

    }
}

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

Кроме того, лучше выполнить настройку UDP для игр, поскольку пропущенный пакет НЕ ДОЛЖЕН препятствовать игровому процессу, а должен обрабатывать его на стороне клиента И на стороне сервера.

...