Создание онлайн-игры: основы

Блоговая публикация пользователя: ProCoder Эта публикация была перенесена из личного блога пользователя в общие разделы уровок сайта.

Создание онлайн-игры: основы

Существует две основные схемы организации онлайн-игр.

1. Клиент – сервер.

Есть множество клиентов, которые обмениваются информацией, передавая ее серверу, а сервер в свою очередь отправляет информацию другим клиентам. Это самая распространенная схема, она всегда используется в веб-серверах и онлайн-играх. Минус всего лишь один: нагрузка на сервер. Схема выглядит следующим образом:


Уроки OpenGL различных тематик: схема клиент - сервер. Рисунок 1. Схема «клиент – сервер».
2. Клиент – клиент.

Тут все проще: клиент соединяется с другим клиентом, и они обмениваются информацией. В этой схеме минусов больше. Мало того, что эта схема поддерживает только двух клиентов, так еще если увеличить их количество, то на одного клиента будут приходиться все остальные. Т.е. нагрузка на сеть и вычислительные способности каждого клиента будут равны нагрузке на сервер. А если у нас в игре 60 клиентов, то каждый другой будет обрабатывать все 59 других, а это занимает много времени. Поэтому если и использовать эту схему, то разве что для игры на двоих, например, шахматы.

Уроки OpenGL различных тематик: схема клиент - клиент. Рисунок 2. Схема «клиент – клиент».
Итак, разберемся все-таки, что делает сервер.

Что есть сервер?

Сервер - это такая вот штука, которая прослушивает нужный порт на предмет подключения. Порт - это точка доступа к серверу, к которой подключаются клиенты. Например, веб-сервер нашего уютненького http://esate.ru работает по порту 80. Чтобы подключиться к его веб-серверу, откроем клиент telnet в ОС Windows. (подробнее о его установке тут) или откроем "Команднуюстроку", и введем следующую команду:

Код:
/*http://esate.ru, ProCoder*/

telnet esate.ru 80


И получим HTML-код:

Код:
/*http://esate.ru, ProCoder*/

<html>
<head><title>400 Bad Request</title></head>
<bodybgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/0.7.67</center>
</body>
</html>

Клиент подключился к серверу esate.ru, сервер отправил ему ответ и отключил клиента от себя. Типичное поведение веб-сервера. Сразу стало ясно, что нам нужно, чтобы написать простой сервер. Нам нужно прослушивать определенный порт на наличие клиентов, как только он появится – решать, что с ним делать, но этим мы займемся чуть позже.

Мы будет использовать протокол TCP/IP.

У платформы .NET есть класс для организации сервера. Называется он TCPListener, а находится в пространстве имен System.Net.Sockets.

Для начала создадим консольный проект на версии .NET Framework 3.5, назовем его, например, EsateGameServer (первое, что пришло в голову).

И еще некоторые приготовления: класс, в котором содержится метод Main() назовем KernelModule. Класс сервера ServerModule.

Начнем.
В "ядре" сервера создаем глобальную ссылку на наш класс ServerModule.

Код:
/*http://esate.ru, ProCoder*/

using System;
using System.Net;
using System.Net.Sockets;

namespace EsateGameServer
{
   classKernelModule
   {
      public static ServerModule Server;
      public static void Main()
      {
         
      }
   }
}

А вот код класса ServerModule:

Код:
/*http://esate.ru, ProCoder*/

using System;
using System.Net;
using System.Net.Sockets;

namespace EsateGameServer
{
   public class ServerModule
   {
      privateTcpListener Server;
      publicServerModule(int Port)
      {
         Server = new TcpListener(IPAddress.Any, Port);
         /*============================================
          * IP Address.Any указанный вместо IP адреса
          * компьютера означает, что сервер будет про-
          * слушивать указанный порт на всех интерфей-
          * сах. Например, у вас к компьютеру подключен
          * интернет и локальная сеть, а значит сервер
          * будет прослушивать и IP интернет интерфейса
          * по указанному порту, и локальный IP.
          =============================================*/
      }
      
      public void Start()
      {
         Server.Start(); //запускаем слушателя
         while (true) // в бесконечном цикле.
         {
            TcpClient client = Server.AcceptTcpClient(); //создаем экземпляр TCPClient, и
                                //направляем ему подключившегося клиента
            Console.WriteLine("Client is connect to the server");
         }
      }
   }
}

В ядре пишем в метод Main() следующие строки:

Код:
/*http://esate.ru, ProCoder*/

Server = new ServerModule(256); //Задаем порт 256
Server.Start(); //стартуем

Теперь давайте скомпилируем и попробуем подключиться к нашему серверу с помощью telnet'а. Открываем консоль, и вводим:

Код:
/*http://esate.ru, ProCoder*/

telnet 127.0.0.1 256
Жмем Enter и в окне telnet'a получаем пустое окно, а в окне нашего сервера получаем сообщение о том, что клиент соединился с сервером. Отлично, если всё получилось именно так.

Мы написали простой сервер, который прослушивает 256 порт, но, если мы попробуем открыть второе окно telnet'a и присоединиться к нашему серверу, клиент не подключится. И правильно, мы ведь прослушиваем 256 порт в одном потоке, поэтому как только сервер словил клиента, он начинает обмен информацией, а про прослушку порта для других клиентов забывает.

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

Добавить комментарий
Расширенный режим добавления комментариев доступен на форуме: загрузка изображений, цитирование, форматирование текста, и т.д.
Ваше имя:
Текст сообщения:
Комментарии (1):
Aleh Lipka
Aleh Lipka,  
Маленькая ремарка.

При работе с TCP соединениями нужно всегда помнить о нескольких вещах:
  1. Если у вас все работает на локальном компьютере, это совершенно не означает, что будет работать в реальных условиях.
  2. Если вы отправляете данные, то это не значит, что вы получите сразу все эти данные за раз или то, что вы получите их вообще. Вы должны ВСЕГДА проверять и обрабатывать ситуации, когда данные пришли не полностью.
На практике, самый простой способ общения с удаленной машиной строится по следующей схеме:
  1. Вы отправляете 4 байта(int) - длину отправляемого массива.
  2. Отправляете уже сам массив байт.
  3. Клиент получает 4 байта длинны.
  4. Рекурсивно получает сам массив уже известной ему длинны.
В противном случае вы рискуете получить не все данные и, скорее всего, так и случится.

Так же хорошей практикой является хранение обертки для клиента в самом сервере.
В такой обертке можно хранить идентификатор, имя и прочие данные, полученные от клиента и, самое главное, экземпляр класса TcpClient для того, что бы вы знали в какой поток слать данные для определенного клиента.
^
Регистрация
Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не забудьте проверить папку спам.
Логин*
Email*
Пароль*
Подтверждение пароля*
 
Логин*
Код*
 
×
Восстановление пароля
Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш Email. Если код не пришел в течении нескольких минут - проверьте папку спам.
Логин

или Email
Логин*
Код подтверждения*
Новый пароль*
Подтверждение пароля*
×
Авторизация
  • Используйте вашу учетную запись на Facebook.com для входа на сайт.
  • Используйте вашу учетную запись VKontakte для входа на сайт.
  • Используйте вашу учетную запись Google для входа на сайт.
Авторизуйтесь с помощью соц. сети или с помощью аккаунта на сайте:
×