На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS

Дорогие друзья! Поздравляем вас с Новым 2018 годом!

Всем удачи, успеха и благополучия!
В новом году ожидаем новых рекордов при подсчёте количества ёлочек на экране ;)


msm.ru
! Предназначение данного раздела
Данный раздел предназначен для публикации уроков и примеров по разработке компьютерных игр любого сорта, в том числе авторских проектов участников нашего форума. Главное условие публикации: необходимо не только выложить свое творение, но и подробно описать процесс его создания, подводные камни и прочие, интересные для собрата-разработчика, вкусности.

Если вы желаете выложить свой проект - пишите в Общеорганизационную тему. Есть какие-то другие вопросы по делу - туда же.

Модераторы: Da$aD
  
> [MMORPG своими руками] 3 Техническая демоверсия, пункты: 3.5
    3.5 Сетевой протокол

    Первая особенность нашего протокола в том, что формат запросов на сервер уже задан. PHP требует, чтобы аргументы подавались в виде:
    ExpandedWrap disabled
      name1=value1&...&nameN=valueN


    Вторая особенность в том, что нам надо пользоваться Cookies для получения/передачи идентификатора сессии, который будет храниться в них под ключом PHPSESSID (это ключ по умолчанию)

    Формат ответа остается за нами. Для удобства мы будем использовать XML. Это позволит нам делегировать проблему парсинга текста специализированным библиотекам. Остается определиться со структурой xml. Конечно, для каждого отдельного ответа сервера набор полей с данными будет разным. Однако один общий элемент будет у всех.

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

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

    Т.е. выглядеть ответ сервера будет примерно так
    ExpandedWrap disabled
      <answer>
              <module>Имя модуля</module>
              <data>Здесь будут находится все данные ответа</data>
      </answer>


    3.5.1 Ввод-вывод клиента

    Теперь попробуем написать функцию отправки запросов серверу
    ExpandedWrap disabled
      public static void httpRequest(String script,Properties args)throws Exception
    Создаем соединение
    ExpandedWrap disabled
      URL url = new URL("http://"+mServerHostName+'/'+script);
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();

    Если у нас уже есть идентификатор сессии, то используем его
    ExpandedWrap disabled
      if(mSessionID!=null)
                  connection.setRequestProperty("Cookie", PHPSESSID+'='+mSessionID);

    Далее записываем параметры запроса в POST, т.е. в поток соединения.
    После окончания записи надо обязательно закрыть поток, чтобы вызвать передачу данных
    ExpandedWrap disabled
              if(args!=null)
              {
                  connection.setDoOutput(true);
                  PrintWriter args_output = new PrintWriter(connection.getOutputStream());
                  boolean first = true;
       
                  for(Entry<Object,Object> entry:args.entrySet())
                  {
                      if(first)
                          first = false;
                      else
                          args_output.print('&');
       
                      args_output.print(entry.getKey());
                      args_output.print("=");
                      args_output.print(entry.getValue());
                  }
       
                  args_output.close();
              }

    Если у нас еще нет идентификатора сессии, то его надо поймать
    ExpandedWrap disabled
      if(mSessionID==null)
              {
                  String cookies = connection.getHeaderField("Set-Cookie");
                  if(cookies!=null)
                  {
                      int start_index = cookies.indexOf(PHPSESSID)+PHPSESSID.length()+1;
       
                      if(start_index!=-1)
                      {
                          int end_index = cookies.indexOf(";");
                          if(end_index==-1)
                              mSessionID = cookies.substring(start_index);
                          else
                              mSessionID = cookies.substring(start_index, end_index);
                      }
                  }
              }

    Делаем предобработку результатов
    ExpandedWrap disabled
      DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
              Element root = parser.parse(connection.getInputStream()).getDocumentElement();
              NodeList answer_nodes = root.getChildNodes();
              String name = null;
              Node data = null;
              for(int i=0;i<answer_nodes.getLength();i++)
              {
                  Node cur_node = answer_nodes.item(i);
                  if(cur_node.getNodeName().equals("module"))
                      name = cur_node.getTextContent();
                  else if(cur_node.getNodeName().equals("data"))
                      data = cur_node;
              }
       
              if(name == null)
                  throw new IOException("Unknown game module in answer");

    и передаем их соотвествующему модулю
    ExpandedWrap disabled
              showModule(name,data);


    Кроме отправки игровых запросов, в ответ на которые присылается хмл, необходимо отправлять запросы на закачку файлов, зависящих от сессии. Например, запращивать каптчу. Для этого мы используем другую функцию, которая напрямую возвращает нам поток с данными.
    ExpandedWrap disabled
      public static InputStream downloadFile(String path) throws IOException
          {
              URL url = new URL("http://"+mServerHostName+'/'+path);
              HttpURLConnection connection = (HttpURLConnection) url.openConnection();
       
              if(mSessionID!=null)
                  connection.setRequestProperty("Cookie", PHPSESSID+'='+mSessionID);
       
              return connection.getInputStream();
          }


    3.5.2 Ввод-вывод сервера

    Парсингом входящих параметров на сервере занимает PHP, однако использовать эти результаты напряму небезопасно. Как минимум стоит проверить интервалы значений для чисел, а также интервалы размеров и наличие кавычек для строк.
    ExpandedWrap disabled
      function getString($name,$min_len,$max_len)
      {
          $param = $_POST[$name];
          $param = mysql_real_escape_string($param);
          if(strlen($param)<$min_len || strlen($param)>$max_len)
              abortExecution("incorrect var $name lenght: $param");
          else
              return $param;
      }
       
      function getInteger($name,$min_val,$max_val)
      {
          $param = (int)$_POST[$name];
          if($param<$min_val || $param>$max_val)
              abortExecution("incorrect var $name value: $param");
          else
              return $param;
      }


    Для вывода информации ввиде хмл удобно использовать стандартный класс PHP - XmlWriter. Однако, т.к. формат ответов имеет некоторую заданную структуру, то мы допишем функцуи обертки, которые будут начинать и заканчивать наш ответ.
    Первая создает заголовок ответа
    ExpandedWrap disabled
      function startAnswer($module)
      {
           $writer = new XmlWriter();
           $writer->openURI("php://output");
           $writer->startDocument("1.0");
           $writer->startElement("answer");
           $writer->startElement("module");
           $writer->text($module);
           $writer->endElement();
           $writer->startElement("data");
           return $writer;
      }

    Вторая осуществляет заверщение и отправку сообщения
    ExpandedWrap disabled
      function sendAnswer($writer)
      {
          $writer->endDocument();
          $writer->flush();
      }
    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
    0 пользователей:


    Рейтинг@Mail.ru
    [ Script Execution time: 0,0844 ]   [ 20 queries used ]   [ Generated: 20.01.18, 06:42 GMT ]