Главная | Форум | Статьи | Фaйлы| Картинки WoW | Профиль | Регистрация | Вход

[ Новые сообщения · Правила форума · Поиск · RSS ]

WoW-Info — информационный World of Warcraft портал

Написание игрового Интернет сервера - Форум

  • Сторінка 1 з 1
  • 1
Написание игрового Интернет сервера
ШайтанДата: Вівторок, 04.01.2011, 18:24 | Сообщение # 1



Шайтан
†HellWoW-Pristton†
Чемпион
Группа: Пользователи
Сообщений: 440

Замечания:

Оффлайн
Введение
Наверняка, Вы играли в такую игру как "Warcraft 3". И было бы просто прекрасно, если Вы играли по Интернету, ибо в этом случае Вы бы могли созерцать и испытать в действии то, что называется "Battle.net". В любом случае я поясню. Это некий "портал" благодаря которому игроки всего Интернета могут запросто найти работающие игровые сервера не выходя из игры. Что значительно облегчает им жизнь, т.к. отпадает необходимость заранее договариваться с соперниками при помощи чатов и подобных средств.

Описание метода
Итак, опишу то что нам понадобится для реализации:
- Хостинг с поддержкой php;
- Ваша игра с работоспособным сетевым кодом :).
Первый пункт я надеюсь не вызывает больших проблем у начинающих "игрописателей", т.к. существует множество сайтов, предоставляющих бесплатный домен с поддержкой php. К примеру, для TFK он был предоставлен сайтом http://mirgames.ru.
А вот со вторым пунктом придется немного попариться, впрочем, это уже тема для отдельной статьи...
Так как в данной статье я использовал PHP, то потребуется знание его основ. Впрочем, при желании, перевод на другой язык написания web страниц не составит большого труда.

Итак, имеем в Интернете домен на котором размещен наш скрипт "арены". Есть игра-клиент, которой нужно узнать кол-во доступных серверов, и при необходимости создать свой.
Что нам нужно от "арены"? Всего-навсего получить список серверов в виде "IP:Port IP:Port IP:Port..." и зарегистрировать новый.
Как это будет происходить? Да очень просто! Посредством HTTP запросов.
Так как нет идеальных решений, какие минусы у данного метода?
- Серверы находящиеся за шлюзом не будут видны остальным клиентам, т.к. даже сама игра-сервер без понятия на каком external порту она висит.
- При падении хостера (сайта) арена шлепнется вместе с ним! Но это относится уже к форс-мажорным обстоятельствам... ;).
А какие же плюсы?
- Относительная простота реализации;
- Легко разместить такую арену в локальной сети;
- Не требует восстановления после различных ЧП :).

Реализация

В этом разделе описаны основные процедуры необходимые для воплощения нашей мечты в реальность. Работа с ареной делится на 2 части:
1) Подача HTTP запросов и обработка ответов игрой;
2) Обработка запроса скриптом на арене.

Всего будет 2 вида запросов: view и ping.
VIEW необходим для получения списка серверов. Будет выглядеть следующим образом:
Запрос: http://host/?action=arena&mode=view.
Ответ : 212.100.15.45:25666 192.10.38.212:25666.
Т.е. в ответе мы видим, что на данный момент на арене находятся 2 сервера на портах 25666.

PING для оповещения арены о том что сервер жив и удалять его из списка пока нет никакой необходимости. Вы могли заметить то, что нет запроса на регистрацию сервера на арене, т.к. в качестве регистрации выступает постоянный "ping" посылаемый им. Сам же запрос "ping" следует посылать раз в несколько десятков секунд (20-40).
Запрос: http://host/?action=arena&mode=ping&port=25666
Ответ нам абсолютно не нужен :).

Реализация на стороне игры
Соответственно нам теперь необходимо знать как отправить HTTP запрос и получить на него ответ. Все проще чем может показаться. Приведу всего одну процедуру использующую возможности WinSock:

Code

function Arena(const mode: string; get: boolean): string;
   const
    host = 'host.ru';
    port = 25666;
   var
    wData : WSADATA;
    addr  : sockaddr_in;
    sock  : integer;
    error : integer;
    buf   : array [0..1023] of Char;
    str   : string;
    phe   : PHostEnt;
   begin
   //Инициализация сокета
   Result := '';
   WSAStartup($0101, wData);
   phe := gethostbyname(PChar(string(host)));
   if phe = nil then
    begin
    WSACleanup;
    Exit;
    end;

   sock := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

   if sock = INVALID_SOCKET then
    begin
    WSACleanup;
    Exit;
    end;

   addr.sin_family := AF_INET;
   addr.sin_port   := htons(80);
   addr.sin_addr   := PInAddr(phe.h_addr_list^)^;

   error := connect(sock, addr, sizeof(addr));
   if error = SOCKET_ERROR then
    begin
    closesocket(sock);
    WSACleanup;
    Exit;
    end;

   // Составляем строку запроса
   str := 'GET http://' + host + '/?action=arena&mode=' + mode;
   if mode = 'ping'
   then str := str + '&port=' + IntToStr(port);
   str := str + ' HTTP/1.0'#13#10#13#10;

   // отправляем
   send(sock, str[1], Length(str), 0);

   // Если нужен ответ то принимаем
   if get then
    begin
    ZeroMemory(@buf, 1024);
    error := recv(sock, buf, 1024, 0);
    while error > 0 do
     begin
     Result := Result + Copy(buf, 0, error);
     error  := recv(sock, buf, 1024, 0);
     end;
    end;
   // Закрываем сокет – завершаем работу с сетью
   closesocket(sock);
   WSACleanup;
        
   // Вырезаем из ответа то что нам нужно, т.е. отрезаем
   // HTTP заголовки
   if get and Result <> ''
   then Result:=Copy(Result, pos(#13#10#13#10, Result)+4,
                     Length(Result));
   end;

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

Code

Str := Arena('view', true); // для получения списка серверов
   Arena('ping', false);       // сообщить арене что наш сервер
                     // живее всех живых

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

Code

procedure Arena_PingThread;
   begin
    Arena('ping', false);
   end;
        
   procedure Arena_Ping;
   var
    id : DWORD;
   begin
    CreateThread(nil, 128, @Arena_PingThread, nil, 0, id);
   end;

После получения списка серверов запросом "view" игра должна разослать им запросы о их текущем состоянии (карта, игроки и т.д.) В этот момент отбрасываются "умершие" сервера, ибо ответа от них не придет.

Реализация на стороне интернет сервера
Итак, с игрой разобрались, теперь осталось написать скрипт!
В запросах мы посылаем ключевое слово "action=arena" благодаря чему помимо арены на данном домене может висеть полноценный сайт.
Для того, чтобы определить адресуется ли данный запрос арене, в index.php необходимо (желательно в самом начале) написать следующее:

Code

if ($action == 'arena')
   {
    include 'arena.php';
    die();
   }

Это означает, что в случае того, когда захотят "пообщаться" с ареной, будет запущен скрипт арены для обработки запроса и дальнейшее выполнение скрипта index.php прекратится.

А вот и сам код arena.php:

Code
<?php
    //В этом файле будет храниться список активных серверов
    $list_file = 'db/arena_list.txt';
    // Узнаем IP адрес отправителя запроса
    $ip = $_SERVER['REMOTE_ADDR'];
    // Читаем номер порта из запроса
    $port = intval($_REQUEST['port']);
    // Это от хитрых кулхацкеров <img src="http://s8.ucoz.net/sm/1/wink.gif" border="0" align="absmiddle" alt="wink">
    if (!($port >= 1024 && $port <= 65500))
     $port = 25666;
    // Читаем файл-список
    $lst = file($list_file);
    // В переменной $time теперь хранится текущее время
    $time = time();
    $j = -1;
    $i = 0;
    // Удаляем “мертвецов” и попутно ищем адрес отправителя
    // в этом списке
    while ($i < count($lst)) {
     $lst[$i] = trim($lst[$i]);
     list($l_ip, $l_port, $l_time) = explode(":", $lst[$i]);
     // Если время с предыдущего пинга превысило 45 секунд
     // – его явно уже нет
     if ($l_time < ($time - 45)) {
      for ($t = $i; $t < count($lst) - 1; $t++)
       $lst[$t] = $lst[$t + 1];
      unset($lst[count($lst) - 1]);
      continue;
     }
     if ($l_ip == $ip) $j = $i;
     $i++;
    }

    // Обработка запроса
    switch ($mode) {
     case 'view':
      for ($i = 0; $i < Count($lst); $i++) {
       // Вывод очередного IP:Port из списка
       list($l_ip, $l_port, $l_time) = explode(":", $lst[$i]);
       echo $l_ip.':'.$l_port.' ';
      }
      break;
     case 'ping':
      if ($j == -1)
       // Если пингуется впервые, значит новый сервер - добавляем
       array_push($lst, $ip.':'.$port.':'.$time);
      else {
       // Обновляем информацию для сервера
       // Заметьте, что при смене порта на сервере
       // на арене он тоже изменится
       list($l_ip, $l_port, $l_time) = explode(":", $lst[$j]);
       $lst[$j] = $l_ip.':'.$port.':'.$time;
       }
      break;
    }

    // Обновляем список серверов в файле-списке
    $f = fopen($list_file, "a+");
    flock($f, LOCK_EX);
    ftruncate($f, 0);
    for ($i = 0; $i < count($lst); $i++)
     fwrite($f, $lst[$i]."\n");
    fflush($f);
    flock($f, LOCK_UN);
    fclose($f);
   ?>

Файл со списком серверов должен находиться в "db/arena_list.txt" с атрибутами разрешающими его изменение.
Вот собственно и все! Дальше дело стоит за Вашей фантазией...
Если заметите какие-либо ошибки или недоработки данной реализации, буду рад Вас выслушать, вместе исправим.



 
  • Сторінка 1 з 1
  • 1
Пошук:

Новые сообщения в темах
Сдам в аренду сервер и хостинг · (Хост Предложения)
Автор: redlaine
Последнее сообщение в 23:53
хаха :D · (Приколы)
Автор: [N1ke]Medved
Последнее сообщение в 18:40
Autobattle - новый боевой бот ... · (Боты для WoW)
Автор: terrikon
Последнее сообщение в 18:39
PvE руководство для Чернокнижн... · (Чернокнижник)
Автор: Darkensand
Последнее сообщение в 18:38
Пустой свиток (Часть 11) · (Истории WoW)
Автор: R_a_Z_o_R
Последнее сообщение в 18:37
Друиды в Катаклизме: Официальн... · (Друид)
Автор: Darkensand
Последнее сообщение в 18:37
[Баг 3.3.5] Фарм ледяных бадже... · (Читы для WoW)
Автор: Darkensand
Последнее сообщение в 18:35
FarmBot (Бот для фарма руды и ... · (Боты для WoW)
Автор: homma
Последнее сообщение в 18:34
Почему мы сражаемся: ролевая и... · (Воин)
Автор: Darkensand
Последнее сообщение в 18:34
Книги по Wold of Warcraft · (Истории WoW)
Автор: R_a_Z_o_R
Последнее сообщение в 18:33
Маг огня в Cataclysm · (Маг)
Автор: Darkensand
Последнее сообщение в 18:33
Как начать играть в World of W... · (Полезно знать)
Автор: Belkmondesh
Последнее сообщение в 18:32
Характеризация профессий · (Профессии)
Автор: Darkensand
Последнее сообщение в 18:31
Что значит для арканов бета те... · (Маг)
Автор: Darkensand
Последнее сообщение в 18:31

Контакты Контакты Copyright WoW-Info — World of Warcraft портал © 2025 | Условия и правила использования ресурса | Реклама / Услуги
WoW-Info портал.World of Warcraft портал — готовые сервера, сайты, картинки, аддоны, патчи, читы, баги, mangos, ArcEmu, TrinityCore, Warcraft 3, новости, Cataclysm...
Яндекс.Метрика Хостинг від uCoz