Многопользовательский сокет-сервер. Введение

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

Неважно, как возникла идея сделать именно Морской бой. Важно только, что от рождения идеи до запуска прошло всего две с половиной недели. Притом, что сервер, арт, клиент и озвучка делались одним единственным человеком. Ввиду отсутствия флэшеров, пришлось самому освоить ActionScript 3 на примере этой самой игры. Но за actionscript ближе к ночи, а сейчас – за сокет-сервера поговорим. :)

Начинается все с постановки задачи. Мы хотим сделать игру, в которой люди могли бы играть друг против друга в обычный школьный морской бой, а если подходящего противника нет – чтобы могли играть с ботом. Ходят по очереди, могут общаться в чате. Ради интереса, добавим небольшую прокачку: сначала играем на мелком поле с 2-3-мя корабликами, дальше, по мере роста, поле растет, кораблей становится больше. Вроде все.

Для подобной задачи, вполне можно обойтись и PHP+MySql асинхронным сервером, но не люблю я их. Да и удобнее это делать на Java – больше возможностей, меньше нагрузки на БД.

Логика и структура всех подобных серверов примерно одинаковая. Коннектор к базе, сокет для подключения новых юзеров, класс “пользователь”, класс “игровая комната”, дополнительные классы, отвечающие за логику игры.

После запуска, сервер ведет себя следующим образом:

1. Конфиг
Грузим конфиги, если они хранятся в виде XML-файлов. Из конфига получаем настройки подключения к БД, количество соединений к БД, номер порта для приема юзеров, ну и что там еще может понадобится. Все остальное, мне кажется, лучше и удобнее хранить в базе.

2. Соединение с БД
При запуске сервера мы создаем пул соединений к базе данных, например 10 штук, который и будем использовать в дальнейшем. Сохраняем инстанс этого пула так, чтобы все классы сервера имели к нему доступ.

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

4. Протокол обмена клиент-сервер
Тут можно фантазировать как угодно: бинарные пакеты, XML, JSON, своя собственная структура. Flash поймет все это нормально, если его запрограммировать. :) Я обычно пользуюсь XML-пакетами, так как они читабельнее при отладке. Если трафика много, можно юзать бинарные.
Обычно, первый пакет, который присылает клиент – пакет авторизации, содержащий его имя/id_вконтакте/и т.п. Сервер проверяет пришедшие данные и либо отсылает пакет об успешной авторизации, либо отсылает клиента нафиг (тут могут быть варианты – как именно послать, и куда).

5. Игровые комнаты
Любая многопользовательская игра может быть представлена в виде нескольких комнат. Как минимум – две: общая комната, куда попадают пользователи после авторизации, она же может быть “лобби” – комнатой для создания и принятия заявок на бой, и комната боя, точнее, комнаты, так как под каждый бой создается отдельная “песочница” для тех, кто участвует в этом бою.
В каждой комнате можно организовать свой чат. Кроме того, если есть необходимость, можно организовать еще глобальный чат, доступный из любой комнаты.

6. Игровая логика
Пользователь входит в лобби и отправляет заявку на бой. Сервер ищет еще одного пользователя, тоже отправившего заявку на бой, находит его, создает комнату-бой, и пихает обоих юзеров туда. Дальше вступает в силу игровая логика.
Пользователи получают данные о противнике (друг о друге), размер игрового поля, положения своих кораблей (мы не стали давать возможность юзерам самим расставлять корабли).
В игровой комнате существует процесс – таймер, управляющий игровыми событиями: начало боя, переход хода и т.п.
Первый пользователь получает пакет “ваш ход”, кликает по вражескому полю, его клиент отсылает серверу пакет с координатами клика. Игровая логика анализирует координаты и рассылает обоим юзерам пакет-результат выстрела: мимо, попал, потопил. Если мимо – происходит передача хода, если попал, ход остается за юзером.
Если был потоплен последний корабль – логика рассылает пакет “конец боя”, говорит, кто победил, какие награды и т.п. Делает нужные записи в класс пользователя и в БД, если надо.
Далее, обоих юзеров выкидывает в общую комнату, после чего процесс повторяется снова.

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

Есть вопросы – задавайте! Хотите знать, когда выйдет следующая статья на эту тему – зарегистрируйтесь либо подпишитесь на RSS :)

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

5 в ответ на Многопользовательский сокет-сервер. Введение:

  1. AlexsWulf пишет:

    Будем надеяться что:
    в течение 1-2-х недель ….
    означает не в течение 1-2-99 недель
    Очень ждем продолжения!
    :)

  2. AlexsWulf пишет:

    Здравствуйте.
    Да очень бы хотелось увидеть продолжение статей, очень интересная инфа.
    Спасибо за публикацию!

  3. Igor пишет:

    Здравствуйте, хочу знать когда выйдет следующая статься, зарегистрировался)

  4. Igor пишет:

    Спасибо, что так быстро отреагировали на мое сообщение и начали писать о сокет-серверах. Продолжение не менее интересное, чем начало, поэтому с нетерпением ждем, что же будет дальше. Думаю, что по ходу дальнейшего повествования появится не мало вопросов))