Реализация XML-RPC протокола на примере многопользовательской игры

Определение принципа вызова удаленных процедур. Проектирование приложения в виде многопользовательской игры "Крестики-нолики" как пример использования стандарта XML-RPC для взаимодействия устройств по сети. Реализация протокола XML-RPC на языке Java.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 17.08.2020
Размер файла 438,0 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Правительство Российской Федерации

Федеральное государственное автономное образовательное учреждение высшего образования

"Национальный исследовательский университет "Высшая школа экономики"

Нижегородский филиал

Факультет информатики, математики и компьютерных наук

Базовая кафедра группы компаний MERA

Выпускная квалификационная работа

На тему: Реализация XML-RPC протокола на примере многопользовательской игры

И.С. Бычков

Нижний Новгород, 2020 г

ОГЛАВЛЕНИЕ

ВВЕДЕНИЕ

1. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

2. ПРАКТИЧЕСКАЯ ЧАСТЬ

ЗАКЛЮЧЕНИЕ

СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ

ПРИЛОЖЕНИЕ

ВВЕДЕНИЕ

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

Существуют различные способы организации взаимодействия пользователей, находящихся в разных сетях. Одним из таких способов является вызов удаленных процедур (RPC - Remote Procedure Call). Такой подход позволяет вызывать методы программы, находящейся в другой сети так, как будто это вызов метода внутри нашей программы. Это позволяет нам произвести выполнение метода в программе на другом устройстве и получить результат выполнения этого действия.

На данный момент можно выделить несколько технологий, которые реализуют вызов удаленных процедур, а одна из них - XML-RPC (eXtensible Markup Language Remote Procedure Call). Данный стандарт отличается своей простотой и понятностью. Используя в качестве кодирования сообщений запроса язык разметки XML и HTTP для транспортировки этих сообщений, он позволяет осуществлять вызов процедур на удаленном приложении или другом устройстве и получать на данный запрос ответ.

Одним из вариантов использования данного протокола является, например, создание простой игры. С его помощью можно реализовать связь между несколькими игроками посредством отправки игроком запроса на удаленное устройство о состоянии игрового процесса на данный момент или запроса на изменение текущего состояния игры. Другой игрок также может осуществлять данные действия.

Актуальность темы

Актуальность работы заключается в изучении и использовании межплатформенной коммуникации между клиентом и сервером на базе XML-RPC протокола. В современном мире используется огромное количество платформ и операционных систем, что рождает необходимость использования межплатформенных механизмов передачи данных. Использование данного стандарта позволяет создавать приложения на различных языках программирования и для разных типов устройств. Подобные приложения, позволяющие взаимодействовать пользователям по сети, пользуются значительной популярностью, особенно в нынешних условиях пандемии. Люди все больше используют различные онлайн-сервисы, в том числе и многопользовательские игры.

Проблематика

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

Цели и задачи работы

Целью данной дипломной работы является реализация протокола XML-RPC на примере многопользовательской игры «Крестики-нолики».

Задачи дипломной работы:

Изучение и определение принципа вызова удаленных процедур;

Описание различных подходов, используемых для реализации данного принципа;

Описание протокола XML-RPC и его особенностей;

Систематизация полученных данных;

Проектирование приложения в виде многопользовательской игры «Крестики-нолики» как пример использования стандарта XML-RPC для взаимодействия устройств по сети;

Реализация протокола XML-RPC на языке Java;

Создание архитектуры приложения «Крестики-нолики» на основе протокола XML-RPC;

Реализация серверной части приложения «Крестики-нолики» на языке Java с использованием технологии XML-RPC;

Реализация клиентской части многопользовательской игры «Крестики-нолики» на языке Java с использованием технологии JavaFX для создания интерфейса приложения.

Данная дипломная работа включает в себя вступление, несколько глав, заключение, список использованной литературы и приложения. Теоретическая часть работы посвящена определению вызова удаленных процедур, примерам реализации данного подхода, описанию протокола XML-RPC и особенностей его работы. Практическая часть работы включает в себя реализацию протокола XML-RPC, а также проектирование и разработку многопользовательской игры «Крестики-нолики» с использованием реализованного протокола.

1. ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

В данной главе описан принцип вызова удаленных процедур, продемонстрированы примеры реализации данного подхода, а также дано описание протокола XML-RPC и особенностей его работы.

Вызов удаленных процедур

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

Вызов удаленных процедур (RPC) - это очень простое расширение идеи вызова процедуры. Его суть заключается в том, что создаются соединения между процедурами, которые выполняются в разных приложениях или на разных машинах. Концептуально нет разницы между локальным вызовом процедуры и удаленным, но они реализованы по-разному, работают по-разному (RPC намного медленнее) и, следовательно, используются для разных целей. Удаленные вызовы преобразуются в формат, который можно понять с другой стороны соединения. Пока две машины согласовывают формат, они могут общаться друг с другом. Вот почему машины Windows могут быть подключены к сети с другими машинами Windows, а компьютеры Mac могут общаться с компьютерами Mac и т.д. Значение стандартизированного кроссплатформенного подхода для RPC заключается в том, что он позволяет компьютерам Unix взаимодействовать с машинами Windows и наоборот.

RPC технически не является протоколом - его лучше рассматривать как общий механизм структурирования распределенных систем. RPC популярен, потому что он основан на семантике локального вызова процедуры - прикладная программа превращает вызов в процедуру, не обращая внимания на то, является ли она локальной или удаленной, и блокирует до тех пор, пока вызов не вернется. Разработчик приложения может в значительной степени не знать, является ли процедура локальной или удаленной, что значительно упрощает его задачу. Когда вызываемые процедуры на самом деле являются методами удаленных объектов на объектно-ориентированном языке, RPC называется удаленным вызовом метода (англ. RMI - Remote Method Invocation). Хотя концепция RPC проста, есть две основные проблемы, которые делают ее более сложной, чем вызовы локальных процедур:

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

Компьютеры, на которых выполняются вызывающий и вызываемый процессы, могут иметь существенно разные архитектуры и форматы представления данных.

Таким образом, полный механизм RPC фактически включает в себя два основных компонента:

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

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

На Рисунке 1 схематически изображено, что происходит, когда клиент вызывает удаленную процедуру. Сначала клиент вызывает локальную заглушку для процедуры, передавая ей аргументы, требуемые процедурой. Эта заглушка скрывает тот факт, что процедура является удаленной, переводя аргументы в сообщение запроса и затем вызывая протокол RPC для отправки сообщения запроса на компьютер сервера. На сервере протокол RPC доставляет сообщение-запрос заглушке на стороне сервера, которая преобразует его в аргументы процедуры и затем вызывает локальную процедуру. После завершения серверной процедуры он возвращается в ответном сообщении и передает его протоколу RPC для передачи обратно клиенту. Протокол RPC на клиенте передает это сообщение заглушке клиента, которая преобразует его в возвращаемое значение, которое возвращается клиентской программе.

Рисунок 1. Механизм RPC.

Реализации вызова удаленных процедур

Существует множество технологий, обеспечивающих RPC:

Distributed Computing Environment/ Remote Procedure Calls (DCE/RPC) - бинарный протокол, транспортной базой служат разные протоколы, например, ТСР/1Р;

Distributed Component Object Model (DCOM) - расширение для DCE/RPC, способно передавать ссылку на объекты и через них вызывать методы этих объектов;

Sun RPC - бинарный протокол на базе UDP, TCP, XDR;

.NET Remoting - бинарный протокол на базе НТТР, UDP, TCP;

JavaScript Object Notation Remote Procedure Calls (JSON-RPC) - для кодирования сообщений использует JSON, B качестве транспорта выступает НТТР или TCP/IP(c версрш 2.0);

Java Remote Method Invocation (Java RMI) - программный вызов удаленных методов на Java.

Simple Object Access Protocol (SOAP) - текстовый протокол на базе НТТР;

eXtensible Markup Language Remote Procedure Call (XML-RPC) - текстовый протокол на базе НТТР.

XML-RPC

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

Рисунок 2. Типы данных XML-RPC

XML-RPC запрос

Запрос в стандарте XML-RPC представляет собой HTTP заголовок и сообщение в формате XML. Корневым элементом XML-сообщения является methodCall. Данный элемент содержит в себе:

methodName - название метода, который вызывается удаленно;

params - параметры вызываемого метода, содержит в себе список элементов с тегом param.

Ниже приведен пример сообщения:

<?xml version="1.0"?>

<methodCall>

<methodName>sum</methodName>

<params>

<param>

<value><i4>2</i4></value>

</param>

<param>

<value><i4>3</i4></value>

</param>

</params>

</methodCall>

HTTP заголовок показывает отправителя, а также содержимое. Пример заголовка приведен ниже:

POST /xmlrpc HTTP 1.0

User-Agent: myClient

Host: 192.168.221.54

Content-Type: text/xml

Content-Length: 188

Полный XML-RPC запрос будет выглядеть так:

POST /xmlrpc HTTP 1.0

User-Agent: myClient

Host: 192.168.221.54

Content-Type: text/xml

Content-Length: 188

<?xml version="1.0"?>

<methodCall>

<methodName>sum</methodName>

<params>

<param>

<value><i4>2</i4></value>

</param>

<param>

<value><i4>3</i4></value>

</param>

</params>

</methodCall>

XML-RPC ответ

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

<?xml version="1.0"?>

<methodResponse>

<params>

<param>

<value><i4>5</i4></value>

</param>

</params>

</methodResponse>

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

XML-RPC ответ так же, как и запрос, содержит заголовок HTTP. Структура заголовка ответа практически такая же, как и у запроса.

HTTP/1.1 200 OK

Date: Sat, 02 May 2020 18:19:07 GMT

Server: server

Connection: close

Content-Type: text/xml

Content-Length: 111

Если в процессе выполнения запроса возникла какая-то проблема, то структура ответа несколько изменяется: вместо элемента params используется элемент fault, в теле которого также содержится единственное значение, показывающее, что что-то пошло не так.

<?xml version="1.0"?>

<methodResponse>

<fault>

<value><string>Error: there is no such method!</string></value>

</fault>

</methodResponse>

Примечательно, что в заголовке ответа всегда указывается код 200, вне зависимости от того, ошибочный ответ или нет.

Особенности XML-RPC

XML-RPC существует уже достаточно долгое время, и, хотя он не поддерживается комитетом по стандартам, он стабилен и открыт для участия сообщества.

Простота XML-RPC - это его самая большая особенность. Данный стандарт чрезвычайно легко понять, реализовать и отладить. Синтаксис настолько прост, что очень легко найти и избежать ошибок.

XML-RPC вызывает методы через его свойство methodName, которое «может содержать только идентифицирующие символы, A-Z в верхнем и нижнем регистре, цифровые символы, 0-9, подчеркивание, точку, двоеточие и косую черту». Для большинства целей этого достаточно, однако это особенно затрудняет, когда вам нужно передать объект в качестве аргумента.

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

Как отмечалось выше, простота также является основным ограничением XML-RPC. Хотя с его помощью можно выполнить почти все необходимые RPC-запросы, есть некоторые вещи, которые вы просто не можете сделать, не приложив серьезных усилий, например, передавать объект в качестве аргумента функции.

2. ПРАКТИЧЕСКАЯ ЧАСТЬ

Практическая часть данной работы включает в себя реализацию протокола XML-RPC на языке Java, а также проектирование и создание многопользовательской игры «Крестики-нолики», имплементирующей данный протокол.

Реализация протокола XML-RPC

Пакет xmlrpc содержит в себе реализацию протокола. Структура данной реализации представлена несколькими классами и пакетами.

В пакете data описано несколько классов, которые представляют из себя типы данных, используемые в протоколе XML-RPC. Все они реализуют интерфейс DataInterface:

Метод serializeXmlRpc используется для создания из объекта строки с тегами и соответствующими типом и значением данных;

Метод parse возвращает объект DataInterface из представления в формате XML.

Данный интерфейс реализуют следующие классы:

MyInt - целочисленный тип данных;

MyDouble - вещественный тип данных;

MyBool - логический тип данных;

MyString - строковый тип данных;

MyBase64 - двоичные данные, кодированные в формате base64;

MyDate - дата и время в формате datetime.iso8601;

MyStruct - массив величин с ключами.

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

CustomException, наследующийся от RuntimeException;

FaultException - наследуется от CustomException, формирует исключение при получении ответа с ошибкой;

InvokeException - наследуется от CustomException, формирует исключение при возникновении ошибки во время выполнения удаленного метода;

ParseException - наследуется от CustomException, формирует исключение при возникновении ошибки парсинга полученного XML файла.

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

Класс MyClient представляет собой объект, который осуществляет взаимодействие с сервером, отправку запросов и получение ответов. Данный класс содержит поля:

serverUri - URI сервера, с которым взаимодействует клиент;

xmlParser - объект класса DocumentBuilder, который используется при парсинге полученного ответа.

Ниже приведены методы класса MyClient:

getServerUri - возвращает URI сервера, с которым взаимодействует клиент;

invokeRemote - осуществляет выполнение запроса на сервер и получение ответа; в ходе работы метода происходит создание HTTP соединения, выполнение POST-запроса с телом сообщения в XML формате, а затем получение ответа на запрос и преобразование возвращенного сообщения в объект класса, реализующего интерфейс DataInterface;

Класс MyServer представляет собой объект, который обрабатывает запросы клиента и отправляет ему ответ. Класс MyServer содержит поля:

controller - объект, который в дальнейшем будет использовать данный класс;

xmlParser - объект класса DocumentBuilder, который используется при парсинге полученного запроса;

mapping - объект внутреннего класса ControllerMapping, с помощью которого хранятся методы объекта, вызывающего класс MyServer;

server - объект HTTP сервера, использующегося для получения запросов и отправки ответов.

Ниже приведены методы класса MyServer:

serve - создание и запуск HTTP сервера;

getServerAddress - получение адреса сервера;

kill - остановка запущенного сервера;

processRequest - метод, в ходе которого обрабатывается запрос, происходит выполнение удаленного метода и возвращается ответ для дальнейшей отправки клиенту;

buildResponse - формирует из объекта, реализующего DataInterface, строку с тегами и соответствующими типом и значением данных;

buildFaultResponse - формирует строку ошибки с тегами и соответствующими типом и значением данных.

Для выполнения удаленной функции используется метод invoke поля mapping, результатом ее выполнения является объект, реализующий DataInterface.

Также в классе Extras содержится метод parseSpecialChild, который используется в некоторых момента парсинга тела сообщения.

Основные требования к приложению

Пользовательские требования:

Приложение должно содержать окно, на котором отображены кнопки старта игры, выхода, обновления игрового поля, поле размером 3х3 клетки, а также текстовое поле, выводящее сообщения об очередности хода и статусе игры;

Приложение должно давать возможность повторного нажатия кнопки старта игры в случае, когда сервер заполнен;

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

Приложение должно давать возможность повторного запуска игры при нажатии на кнопку старта;

Технические требования:

Приложение должно представлять из себя веб-сервис c клиентской и серверными частями; Серверная часть сервиса должна быть написана на языке Java с использованием компонентов разработанного XML-RPC протокола;

Клиентская часть сервиса должна быть написана на языке Java с использованием компонентов разработанного XML-RPC протокола, а также фреймворка JavaFX для создания интерфейса приложения.

Инструменты

Java версии 1.8.0_251;

Intellij IDEA;

JavaFX фреймворк;

IntelliJ IDEA -- интегрированная среда разработки программного обеспечения для многих языков программирования, в частности Java, JavaScript, Python, разработанная компанией JetBrains.

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

Архитектура приложения

Приложение представляет собой веб-сервис, состоящий из двух частей:

Клиентская часть приложения;

Серверная часть приложения.

Серверная часть

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

first - является индикатором того, подключился ли первый игрок к серверу;

second - является индикатором того, подключился ли второй игрок к серверу;

field - двумерный массив, который содержит текущие символы игрового поля;

playable - является индикатором того, есть ли возможность продолжать игру;

draw - индикатор ничьей в партии;

lastX - номер строки, где был поставлен последний символ;

lastY - номер столбца, где был поставлен последний символ;

lastSym - последний поставленный символ;

В данном классе определены следующие методы:

checkstate - проверка состояния игрового поля на наличие выигрышных комбинаций; в случае ее наличия меняется значение переменной playable;

clean - используется для очистки поля field;

init - удаленная функция, которая используется для инициализации клиентов сервера и возвращает им символ для игры;

returnField - удаленная функция, возвращает значение символа клетки по запрошенным координатам;

returnLastX - удаленная функция, возвращает значение строки, в которой был поставлен последний символ;

returnLastY - удаленная функция, возвращает значение столбца, в котором был поставлен последний символ;

returnTurn - удаленная функция, возвращает значение последнего поставленного символа;

returnPlayable - удаленная функция, возвращает значение индикатора возможности продолжать игру;

setField - удаленная функция, добавляет на поле указанный символ по указанным координатам.

При вызове метода main происходит создание объекта класса MyServer с указанием нашего класса TicTacToeServer, а затем производится запуск сервера с помощью метода serve;

Клиентская часть

Клиентская часть программы состоит из нескольких классов и fxml-файла:

MyServerUser;

Field;

Field.fxml;

Main.

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

init - возвращает клиенту символ, использующийся для игры;

getTurn - возвращает последний поставленный символ в игре, что используется для определения очередности хода;

getField - возвращает значение символа по указанным координатам;

getPlayable - возвращает значение индикатора возможности продолжать игру;

getDraw - возвращает значение индикатора ничьей;

setField - добавляет на поле указанный символ по указанным координатам.

Стоит отметить, что сервер возвращает ответы в формате данных, реализующих DataInterface, поэтому при выполнении методов класса MyServerUser происходит их преобразование в стандартные типы.

Класс Field является контроллером интерфейса программы, с помощью которого происходит изменение внешнего вида окна приложения и его возможностей. Класс содержит элемент sym, в котором указывается символ, использующийся пользователем, а также несколько полей, помеченных аннотацией @FXML, которая показывает, что данные поля являются объектами интерфейса программы:

button (9 шт.) - клетки на игровом поле;

startButton - кнопка запуска игры;

quitButton - кнопка выхода из приложения;

updButton - кнопка обновления состояния игрового поля;

label - поле с текстом, которое отображает очередность хода или результат игры;

Ниже представлены функции класса Field:

makeArray - объединение клеток в общий массив;

handleButtonAction - обработчик события нажатия на одну из клеток поля; производит изменение данной клетки, проверку состояния игры;

handleQuitAction - обработчик события нажатия на кнопку выхода из приложения;

handleStartAction - обработчик события нажатия на кнопку старта игры;

handleUpdAction - обработчик события нажатия на кнопку обновления игрового поля;

disableAllButtons - отключение возможности нажатия на клетки игрового поля;

enableAllButtons - включение возможности нажатия на клетки игрового поля;

clearAllButtons - очистка клеток игрового поля;

symFill - настройка цвета символов на игровом поле;

Файл Field.fxml содержит в себе разметку интерфейса приложения, а также указывает на контроллер Field, управляющий изменениями интерфейса.

Класс Main при вызове метода main загружает на экран пользователя сцену с интерфейсом, описанным в Field.fxml, для дальнейшего использования. На рисунке ниже представлен интерфейс приложения при запуске.

Рисунок 3. Интерфейс приложения "Крестики-нолики"

Пример работы приложения

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

При нажатии на кнопку Start в зависимости от очередности хода игрок может или сделать ход на игровом поле, или обновить состояние игрового поля в ожидании хода противника:

Первый игрок при нажатии клетки на игровом поле ставит присвоенный ему символ и переходит в режим ожидания. Второй игрок при нажатии кнопки update обновляет состояние игрового поля и получает право хода.

В конце игровой партии каждый из игроков получает следующий результат:

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

После завершения игровой партии игроки могут сыграть еще или осуществить выход из приложения.

ЗАКЛЮЧЕНИЕ

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

В практической части работы был реализован данный протокол на языке Java. Для демонстрации работы протокола XML-RPC было создано клиент-серверное приложение в виде многопользовательской игры «Крестики-нолики». Данное приложение позволяет двум пользователям сыграть партию в крестики нолики, а для осуществления связи между устройствами используется разработанный протокол, с помощью которого игроки получают информацию с сервера о текущем состоянии партии.

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

приложение игра сеть протокол

СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ

1. Cerami, Ethan. Web services essentials. O'Reilly, 2002. - 304 p. - ISBN: 0-596-00224-6.

2. Laurent Simon, Johnston Joe, Dumbill Edd. ProgrammingWeb Serviceswith XML-RPC. O'Reilly, 2001. - 230 p. - ISBN: 0-596-00119-3.

ПРИЛОЖЕНИЕ

DataInterface.java

public interface DataInterface {

String serializeXmlRpc();

static DataInterface parse(Node xml) {

if (xml instanceof Element) {

switch (((Element)xml).getTagName()) {

case "base64":

return new MyBase64(xml.getTextContent());

case "boolean":

return MyBool.forValue(!xml.getTextContent().equals("0"));

case "dateTime.iso8601":

return new MyDate(Instant.parse(xml.getTextContent()));

case "double":

return new MyDouble(Double.parseDouble(xml.getTextContent()));

case "int":

case "i4":

return new MyInt(Integer.parseInt(xml.getTextContent()));

case "string":

return new MyString(xml.getTextContent());

case "struct": {

MyStruct<DataInterface> struct = new MyStruct<>();

NodeList xmlChildren = xml.getChildNodes();

for (int i = 0; i < xmlChildren.getLength(); i++) {

Node memberXml = xmlChildren.item(i);

if (memberXml instanceof Element && ((Element)memberXml).getTagName().equals("member")) {

String name = null;

Node value = null;

NodeList memberXmlChildren = memberXml.getChildNodes();

for (int j = 0; j < memberXmlChildren.getLength(); j++) {

Node propXml = memberXmlChildren.item(j);

if (propXml instanceof Element) {

switch (((Element)propXml).getTagName()) {

case "name":

name = propXml.getTextContent().trim();

break;

case "value":

value = Extras.parseSpecialChild(propXml);

break;

}

}

}

if (name != null && value != null) {

struct.put(name, parse(value));

}

}

}

return struct;

}

default:

throw new ParseException("Type of XML-RPC is bad!: " + ((Element)xml).getTagName());

}

} else {

return new MyString(xml.getTextContent());

}

}

}

MyInt.java

package xmlrpc.data;

public class MyInt implements DataInterface {

public static final MyInt ZERO = new MyInt(0);

public final int value;

public MyInt(int value) {

this.value = value;

}

@Override

public String serializeXmlRpc() {

return "<i4>" + value + "</i4>";

}

@Override

public int hashCode() {

return Integer.hashCode(value);

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyInt && value == ((MyInt)obj).value;

}

@Override

public String toString() {

return Integer.toString(value);

}

}

MyDouble.java

package xmlrpc.data;

public class MyDouble implements DataInterface {

public static final MyDouble ZERO = new MyDouble(0D);

public final double value;

public MyDouble(double value) {

this.value = value;

}

@Override

public String serializeXmlRpc() {

return "<double>" + value + "</double>";

}

@Override

public int hashCode() {

return Double.hashCode(value);

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyDouble && value == ((MyDouble)obj).value;

}

@Override

public String toString() {

return Double.toString(value);

}

}

MyBool.java

package xmlrpc.data;

public enum MyBool implements DataInterface {

TRUE(true),

FALSE(false);

public static MyBool forValue(boolean value) {

return value ? TRUE : FALSE;

}

public final boolean value;

MyBool(boolean value) {

this.value = value;

}

@Override

public String serializeXmlRpc() {

return value ? "<boolean>1</boolean>" : "<boolean>0</boolean>";

}

@Override

public String toString() {

return Boolean.toString(value);

}

}

MyString.java

package xmlrpc.data;

public class MyString implements DataInterface {

public final String value;

public MyString(String value) {

this.value = value;

}

public MyString(Object value) {

this(value.toString());

}

@Override

public String serializeXmlRpc() {

return "<string>" + value + "</string>";

}

@Override

public int hashCode() {

return value.hashCode();

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyString && value.equals(((MyString)obj).value);

}

@Override

public String toString() {

return value;

}

}

MyBase64.java

package xmlrpc.data;

import java.nio.charset.Charset;

import java.nio.charset.StandardCharsets;

import java.util.Base64;

public class MyBase64 implements DataInterface {

public static MyBase64 forUtf8(String str) {

return forString(str, StandardCharsets.UTF_8);

}

public static MyBase64 forString(String str, Charset charset) {

return forBytes(str.getBytes(charset));

}

public static MyBase64 forBytes(byte[] data) {

return new MyBase64(Base64.getEncoder().encodeToString(data));

}

public final String data;

public MyBase64(String data) {

this.data = data;

}

public String decodeUtf8() {

return decodeString(StandardCharsets.UTF_8);

}

public String decodeString(Charset charset) {

return new String(decodeBytes(), charset);

}

public byte[] decodeBytes() {

return Base64.getDecoder().decode(data);

}

@Override

public String serializeXmlRpc() {

return "<base64>" + data + "</base64>";

}

@Override

public int hashCode() {

return ~data.hashCode();

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyBase64 && data.equals(((MyBase64)obj).data);

}

@Override

public String toString() {

return "b64:" + data;

}

}

MyDate.java

package xmlrpc.data;

import java.time.Instant;

public class MyDate implements DataInterface {

public final Instant time;

public MyDate(Instant time) {

this.time = time;

}

@Override

public String serializeXmlRpc() {

return "<dateTime.iso8601>" + time.toString() + "</dateTime.iso8601>";

}

@Override

public int hashCode() {

return time.hashCode();

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyDate && time.equals(((MyDate)obj).time);

}

@Override

public String toString() {

return time.toString();

}

}

MyStruct.java

package xmlrpc.data;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

import java.util.function.Supplier;

import java.util.stream.Collectors;

public class MyStruct<T extends DataInterface> implements DataInterface {

private final Map<String, T> entries = new HashMap<>();

public MyStruct(Map<String, T> source) {

entries.putAll(source);

}

public MyStruct(MyStruct<T> source) {

entries.putAll(source.entries);

}

public MyStruct() {

}

public void put(String key, T value) {

entries.put(key, value);

}

public T get(String key) {

return entries.get(key);

}

public T computeIfAbsent(String key, Supplier<T> valueFactory) {

return entries.computeIfAbsent(key, k -> valueFactory.get());

}

public Set<Map.Entry<String, T>> getEntries() {

return entries.entrySet();

}

@Override

public String serializeXmlRpc() {

StringBuilder sb = new StringBuilder("<struct>");

for (Map.Entry<String, T> entry : entries.entrySet()) {

sb.append("<member><name>")

.append(entry.getKey())

.append("</name><value>")

.append(entry.getValue().serializeXmlRpc())

.append("</value></member>");

}

return sb.append("</struct>").toString();

}

@Override

public int hashCode() {

return entries.hashCode();

}

@Override

public boolean equals(Object obj) {

return obj instanceof MyStruct && entries.equals(((MyStruct)obj).entries);

}

@Override

public String toString() {

return "{" + entries.entrySet().stream()

.map(e -> e.getKey() + ": " + e.getValue()).collect(Collectors.joining(", ")) + "}";

}

}

CustomException.java

package xmlrpc.errors;

public abstract class CustomException extends RuntimeException {

public CustomException(String message) {

super(message);

}

public CustomException(String message, Throwable cause) {

super(message, cause);

}

}

InvokeException.java

package xmlrpc.errors;

public class InvokeException extends CustomException {

public InvokeException(String message) {

super(message);

}

public InvokeException(String message, Throwable cause) {

super(message, cause);

}

}

FaultException.java

package xmlrpc.errors;

public class FaultException extends CustomException {

private final int faultCode;

private final String faultMessage;

public FaultException(int faultCode, String faultMessage) {

super("XML-RPC fault " + faultCode + ": " + faultMessage);

this.faultCode = faultCode;

this.faultMessage = faultMessage;

}

public int getFaultCode() {

return faultCode;

}

public String getFaultMessage() {

return faultMessage;

}

}

ParseException.java

package xmlrpc.errors;

public class ParseException extends CustomException {

public ParseException(String message) {

super(message);

}

public ParseException(String message, Throwable cause) {

super(message, cause);

}

}

MyClient.java

package xmlrpc;

public class MyClient {

private final URI serverUri;

private final DocumentBuilder xmlParser;

public MyClient(URI serverUri) {

this.serverUri = serverUri;

try {

xmlParser = DocumentBuilderFactory.newInstance().newDocumentBuilder();

} catch (ParserConfigurationException e) {

throw new IllegalStateException("Init of XML parser failed!", e);

}

}

public URI getServerUri() {

return serverUri;

}

public DataInterface invokeRemote(String methodName, DataInterface... params) throws IOException {

HttpURLConnection conn = (HttpURLConnection)serverUri.toURL().openConnection();

conn.setRequestMethod("POST");

conn.setRequestProperty("Content-Type", "application/xml");

conn.setDoOutput(true);

try (OutputStream streamOut = conn.getOutputStream()) {

streamOut.write(buildRequest(methodName, params).getBytes(StandardCharsets.UTF_8))

}

Element resXml;

try (InputStream streamIn = conn.getInputStream()) {

if (conn.getResponseCode() >= 400) {

throw new IOException(String.format("Http %d: %s", conn.getResponseCode(), conn.getResponseMessage()));

}

resXml = xmlParser.parse(streamIn).getDocumentElement();

} catch (SAXException e) {

throw new ParseException("Parsing XML-RPC response is failed!", e);

}

Node resultNode = null;

boolean fault = false;

if (resXml.getTagName().equals("methodResponse")) {

NodeList resXmlChildren = resXml.getChildNodes();

for (int i = 0; i < resXmlChildren.getLength(); i++) {

Node paramsXml = resXmlChildren.item(i);

Node valueContXml = null;

fault = false;

if (paramsXml instanceof Element) {

if (((Element)paramsXml).getTagName().equals("fault")) {

valueContXml = paramsXml;

fault = true;

} else if (((Element)paramsXml).getTagName().equals("params")) {

NodeList paramsXmlChildren = paramsXml.getChildNodes();

for (int j = 0; j < paramsXmlChildren.getLength(); j++) {

Node paramXml = paramsXmlChildren.item(j);

if (paramXml instanceof Element && ((Element)paramXml).getTagName().equals("param")) {

valueContXml = paramXml;

break;

}

}

}

if (valueContXml != null) {

resultNode = unwrapValueContainer(valueContXml.getChildNodes());

break;

}

}

}

}

if (resultNode == null) {

throw new ParseException("XML-RPC response is bad!");

}

if (fault) {

MyStruct<?> faultData = (MyStruct<?>) DataInterface.parse(resultNode);

throw new FaultException(

((MyInt)faultData.get("faultCode")).value,

((MyString)faultData.get("faultString")).value);

} else {

return DataInterface.parse(resultNode);

}

}

private static String buildRequest(String methodName, DataInterface[] params) {

StringBuilder sb = new StringBuilder("<methodCall><methodName>")

.append(methodName)

.append("</methodName><params>");

for (DataInterface param : params) {

sb.append("<param><value>").append(param.serializeXmlRpc()).append("</value></param>");

}

return sb.append("</params></methodCall>").toString();

}

@Nullable

private static Node unwrapValueContainer(NodeList valueContChildren) {

for (int i = 0; i < valueContChildren.getLength(); i++) {

Node valueXml = valueContChildren.item(i);

if (valueXml instanceof Element && ((Element)valueXml).getTagName().equals("value")) {

return valueXml.getFirstChild();

}

}

return null;

}

}

MyServer.java

package xmlrpc;

public class MyServer {

private final Object controller;

private final ControllerMapping mapping;

private final DocumentBuilder xmlParser;

@Nullable

private HttpServer server = null;

public MyServer(Object controller) {

this.controller = controller;

this.mapping = ControllerMapping.computeMapping(controller.getClass());

try {

xmlParser = DocumentBuilderFactory.newInstance().newDocumentBuilder();

} catch (ParserConfigurationException e) {

throw new IllegalStateException("Failed to initialize XML parser!", e);

}

}

public void serve() throws IOException {

serve(new InetSocketAddress("0.0.0.0", 8765));

}

public void serve(InetSocketAddress address) throws IOException {

serve(address, Executors.newSingleThreadExecutor());

}

public void serve(InetSocketAddress address, Executor executor) throws IOException {

if (server != null) {

throw new IllegalStateException("Error: already start server!");

}

server = HttpServer.create(address, 0);

server.createContext("/", req -> {

String response;

try {

DataInterface result = processRequest(req);

response = buildResponse(result != null ? result : MyInt.ZERO);

} catch (Throwable e) {

MyStruct<DataInterface> errResponse = new MyStruct<>();

errResponse.put("faultCode", new MyInt(-1));

errResponse.put("faultString", new MyString(e));

response = buildFaultResponse(errResponse);

}

try (BufferedOutputStream res = new BufferedOutputStream(req.getResponseBody())) {

byte[] responseData = response.getBytes(StandardCharsets.UTF_8);

req.sendResponseHeaders(200, responseData.length);

res.write(responseData);

}

});

server.setExecutor(executor);

server.start();

}

public InetSocketAddress getServerAddress() {

if (server == null) {

throw new IllegalStateException("Error: server isn`t started!");

}

return server.getAddress();

}

public void kill() {

if (server == null) {

throw new IllegalStateException("Error: server isn`t started!");

}

server.stop(0);

server = null;

}

@Nullable

private DataInterface processRequest(HttpExchange req) throws Throwable {

Element reqXml;

try (InputStream reqBody = req.getRequestBody()) {

reqXml = xmlParser.parse(reqBody).getDocumentElement();

} catch (SAXException e) {

throw new ParseException("Parsing XML-RPC request is failed!", e);

}

String methodName = null;

List<Node> reqParamNodes = new ArrayList<>();

if (reqXml.getTagName().equals("methodCall")) {

NodeList reqXmlChildren = reqXml.getChildNodes();

for (int i = 0; i < reqXmlChildren.getLength(); i++) {

Node reqXmlChild = reqXmlChildren.item(i);

if (reqXmlChild instanceof Element) {

switch (((Element)reqXmlChild).getTagName()) {

case "methodName":

methodName = reqXmlChild.getTextContent().trim();

break;

case "params": {

NodeList paramsXmlChildren = reqXmlChild.getChildNodes();

for (int j = 0; j < paramsXmlChildren.getLength(); j++) {

Node paramXml = paramsXmlChildren.item(j);

if (paramXml instanceof Element && ((Element)paramXml).getTagName().equals("param")) {

NodeList paramXmlChildren = paramXml.getChildNodes();

for (int k = 0; k < paramXmlChildren.getLength(); k++) {

Node valueXml = paramXmlChildren.item(k);

if (valueXml instanceof Element && ((Element)valueXml).getTagName().equals("value")) {

reqParamNodes.add(Extras.parseSpecialChild(valueXml));

}

}

}

}

break;

}

}

}

}

}

if (methodName == null) {

throw new ParseException("XML-RPC request is bad!");

}

DataInterface[] params = new DataInterface[reqParamNodes.size()];

for (int i = 0; i < params.length; i++) {

params[i] = DataInterface.parse(reqParamNodes.get(i));

}

return mapping.invoke(controller, methodName, params);

}

private static String buildResponse(DataInterface data) {

return "<methodResponse><params><param><value>" + data.serializeXmlRpc() + "</value></param></params></methodResponse>";

}

private static String buildFaultResponse(DataInterface data) {

return "<methodResponse><fault><value>" + data.serializeXmlRpc() + "</value></fault></methodResponse>";

}

private static class ControllerMapping {

private static final Map<Class<?>, ControllerMapping> mappingCache = new HashMap<>();

public static ControllerMapping computeMapping(Class<?> type) {

return mappingCache.computeIfAbsent(type, ControllerMapping::new);

}

private final Map<String, Method> methodMap = new HashMap<>();

private ControllerMapping(Class<?> type) {

for (Method method : type.getDeclaredMethods()) {

XmlRpcAnnot annot = method.getAnnotation(XmlRpcAnnot.class);

if (annot != null) {

String annotMethodName = annot.name();

if (annotMethodName.isEmpty()) {

annotMethodName = method.getName();

}

method.setAccessible(true);

methodMap.put(annotMethodName, method);

}

}

}

@Nullable

DataInterface invoke(Object controller, String methodName, DataInterface[] params) throws Throwable {

Method method = methodMap.get(methodName);

if (method == null) {

throw new InvokeException("Could not find matching RPC method: " + methodName);

}

try {

return (DataInterface)method.invoke(controller, (Object[])params);

} catch (IllegalAccessException e) {

throw new IllegalStateException("Cached method in bad state!", e);

} catch (IllegalArgumentException e) {

throw new InvokeException("Bad arguments for RPC invocation!", e);

} catch (InvocationTargetException e) {

throw e.getTargetException();

}

}

}

}

Extras.java

package xmlrpc;

public class Extras {

public static Node parseSpecialChild(Node parent) {

NodeList children = parent.getChildNodes();

for (int k = 0; k < children.getLength(); k++) {

Node child = children.item(k);

if (child instanceof Element) {

return child;

}

}

return parent.getFirstChild();

}

}

XmlRpcAnnot.java

package xmlrpc;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface XmlRpcAnnot {

String name() default "";

}

TicTacToeServer.java

package server;

public class TicTacToeServer {

public static boolean first;

public static boolean second;

public static boolean playable = true;

public static boolean draw = false;

public static String[][] field = new String[3][3];

public static int lastX;

public static int lastY;

public static String lastSym = "X";

public void checkState() {

if (!field[0][0].equals("-") && field[0][0].equals(field[0][1]) && field[0][0].equals(field[0][2]) ||

!field[1][0].equals("-") && field[1][0].equals(field[1][1]) && field[1][0].equals(field[1][2]) ||

!field[2][0].equals("-") && field[2][0].equals(field[2][1]) && field[2][0].equals(field[2][2]) ||

!field[0][0].equals("-") && field[0][0].equals(field[1][0]) && field[0][0].equals(field[2][0]) ||

!field[0][1].equals("-") && field[0][1].equals(field[1][1]) && field[0][1].equals(field[2][1]) ||

!field[0][2].equals("-") && field[0][2].equals(field[1][2]) && field[0][2].equals(field[2][2]) ||

!field[0][0].equals("-") && field[0][0].equals(field[1][1]) && field[0][0].equals(field[2][2]) ||

!field[2][0].equals("-") && field[2][0].equals(field[1][1]) && field[2][0].equals(field[0][2])) {

playable = false;

first = false;

second = false;

}

}

public void setDraw() {

if (playable && !field[0][0].equals("-") &&

!field[0][1].equals("-") &&

!field[0][2].equals("-") &&

!field[1][0].equals("-") &&

!field[1][1].equals("-") &&

!field[1][2].equals("-") &&

!field[2][0].equals("-") &&

!field[2][1].equals("-") &&

!field[2][2].equals("-")) {

draw = true;

first = false;

second = false;

}

}

@XmlRpcAnnot

public MyBool returnDraw() {

return MyBool.forValue(draw);

}

public static void main(String[] args) throws IOException {

System.out.println(field[0][0]);

MyServer server = new MyServer(new TicTacToeServer());

server.serve();

System.out.println("WORKS!!!");

}

private void clean() {

for (int i = 0; i < 3; i++) {

for (int j = 0; j < 3; j++) {

field[i][j] = "-";

}

}

}

@XmlRpcAnnot

public MyString init() {

if (!first) {

clean();

playable = true;

draw = false;

first = true;

return new MyString("X");

} else if (!second) {

second = true;

return new MyString("O");

} else {

return new MyString("foo");

}

}

@XmlRpcAnnot

public MyString returnField(MyInt x, MyInt y) {

return new MyString(field[x.value][y.value]);

}

@XmlRpcAnnot

public MyInt returnLastX() {

return new MyInt(lastX);

}

@XmlRpcAnnot

public MyInt returnLastY() {

return new MyInt(lastY);

}

@XmlRpcAnnot

public MyBool returnPlayable() {

return MyBool.forValue(playable);

}

@XmlRpcAnnot

public MyString returnTurn() {

return new MyString(lastSym);

}

@XmlRpcAnnot

public MyBool setField(MyInt x, MyInt y, MyString s) {

lastX = x.value;

lastY = y.value;

lastSym = s.value;

field[x.value][y.value] = s.value;

checkState();

setDraw();

return MyBool.forValue(playable);

}

}

MyClientUser.java

package client.presenter;

public class MyClientUser {

private boolean playable = true;

private MyClient client = new MyClient(URI.create("http://127.0.0.1:8765"));

public MyClient getClient() {

return client;

}

public String init() throws CustomException, IOException {

MyString sym = (MyString) client.invokeRemote("init");

return sym.value;

}

public boolean setField(int i, String sym) throws IOException {

MyBool tmp = (MyBool) client.invokeRemote("setField", new MyInt(i/3), new MyInt(i%3),

new MyString(sym));

System.out.println(tmp.value);

return tmp.value;

}

public String getTurn() throws IOException {

MyString sym = (MyString) client.invokeRemote("returnTurn");

return sym.value;

}

public boolean getPlayable() throws IOException {

MyBool pl = (MyBool) client.invokeRemote("returnPlayable");

return pl.value;

}

public int getField() throws IOException {

MyInt x = (MyInt) client.invokeRemote("returnLastX");

MyInt y = (MyInt) client.invokeRemote("returnLastY");

return 3*x.value+y.value;

}

public boolean getDraw() throws IOException {

MyBool draw = (MyBool)client.invokeRemote("returnDraw");

return draw.value;

}

}

Field.java

package client.view;

public class Field {

private MyClientUser user = new MyClientUser();

private String sym;

@FXML

private Button startButton;

@FXML

private Button quitButton;

public void handleQuitAction(ActionEvent event) throws IOException {

Stage stage = (Stage) quitButton.getScene().getWindow();

stage.close();

}

public void handleStartAction(ActionEvent event) throws IOException {

clearAllButtons();

sym = user.init();

if (sym.equals("foo")) {

label.setText("Server is full");

quitButton.setDisable(false);

return;

}

makeArray();

if (sym.equals("X")) {

enableAllButtons();

label.setText("Your turn");

quitButton.setDisable(true);

}

if (sym.equals("O")) {

label.setText("wait");

updButton.setDisable(false);

}

startButton.setDisable(true);

}

@FXML

private Button button11;

@FXML

private Button button12;

@FXML

private Button button13;

@FXML

private Button button21;

@FXML

private Button button22;

@FXML

private Button button23;

@FXML

private Button button31;

@FXML

private Button button32;

@FXML

private Button button33;

private ArrayList<Button> buttons = new ArrayList();

public void makeArray() {

buttons.add(button11);

buttons.add(button12);

buttons.add(button13);

buttons.add(button21);

buttons.add(button22);

buttons.add(button23);

buttons.add(button31);

buttons.add(button32);

buttons.add(button33);

}

@FXML

public Label label;

@FXML

private Button updButton;

@FXML

public void handleUpdAction(ActionEvent event) throws IOException {

...

Подобные документы

  • Знакомство с интерфейсом пользователя и сценарием использования программы игры в крестики и нолики. Функциональные и нефункциональные требования для персонального компьютера. Исключительные ситуации и реакция программы. Пример кода игры и комментарии.

    курсовая работа [236,5 K], добавлен 27.01.2014

  • Общая характеристика языков программирования. Краткий обзор C, C++, Java, PHP, Python, Delphi и Visual Basic. Процесс разработки программы игра "Крестики и нолики" с помощью AppWizard. Компиляция и компоновка модулей, определение интерфейса приложения.

    курсовая работа [2,5 M], добавлен 27.05.2014

  • Разработка популярной развлекательной игры крестики-нолики. Возможность играть с компьютером, который играет согласно созданному алгоритму. Новые возможности Visual Studio. Легкое усвоение программы. Удобный интерфейс - "визитная карточка" приложения.

    курсовая работа [74,6 K], добавлен 20.12.2009

  • Разработка и создание игры "Змейка". Использование динамически-активных принципов языка Java. Графические объекты программы. Описание игры, правила, теоретические сведения. Классы приложения. Типы данных. Реализация. Метод. Объект. Блок-схема игры.

    курсовая работа [12,4 K], добавлен 18.06.2008

  • Разработка программы логической игры в "крестики-нолики" пять в ряд на поле размера 15х15 клеток с применением графики на языке Pascal с использованием объектно-ориентированного программирования. Структура алгоритма программы и описание ее работы.

    курсовая работа [821,5 K], добавлен 13.02.2012

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

    методичка [819,6 K], добавлен 12.05.2013

  • Разработка программы игры в крестики-нолики. Примеры игровой ситуации на игровом поле. Описание входных и выходных данных, переменных и функций программы. Реализация алгоритма работы программы на языке C++. Текст программы и примеры ее выполнения.

    курсовая работа [352,8 K], добавлен 14.04.2011

  • История развития языка программирования Java. История тетриса - культовой компьютерной игры, изобретённой в СССР. Правила проведения игры, особенности начисления очков. Создание интерфейса программы, ее реализация в среде Java, кодирование, тестирование.

    курсовая работа [168,1 K], добавлен 27.09.2013

  • Проект программы "Крестики-нолики". Блок-схема алгоритма. Описание работы программного продукта. Инструкция по инсталляции. Инструкция программисту, возможность доработки с целью упрощения исполняемых кодов. Инструкция по проверке и тестированию.

    курсовая работа [235,8 K], добавлен 05.12.2009

  • Разработка аналога игры "Крестики-нолики", где игроки выбирают размер поля. Правила игры. Интерфейс программы. Главная функция main. Класс XO. Метод вывода поля и хода игроков. Методы поиска крестиков, ноликов. Методы проверки выигрышных ситуаций игроков.

    курсовая работа [281,5 K], добавлен 30.01.2018

  • Средства выделения и освобождения памяти. Динамические структуры данных. Связные линейные списки и их машинное представление. Структура одно- и двухсвязного списка. Реализация операций над связными линейными списками. Разработка программы на языке С++.

    курсовая работа [944,7 K], добавлен 14.03.2015

  • Разработка алгоритма, выполняющего поиск наилучшего решения на каждый ход в игре "крестики-нолики" (используя минимальный алгоритм). Обоснование выбора программных средств для решения задачи. Блок-схема интеллектуального алгоритма реализации программы.

    контрольная работа [380,0 K], добавлен 28.04.2014

  • Сетевые возможности языков программирования. Преимущества использования Java-апплетов. Классы, входящие в состав библиотеки java.awt. Создание пользовательского интерфейса. Сокетное соединение с сервером. Графика в Java. Значения составляющих цвета.

    курсовая работа [508,1 K], добавлен 10.11.2014

  • Описание существующих технологий, поддерживающих концепцию распределенных объектных систем. Особенности технологии DCOM. Разработка параметров приложения. Выбор инструмента разработки и его обоснование. Схема взаимодействия для локального приложения.

    курсовая работа [769,8 K], добавлен 05.01.2013

  • Java RMI как тип удаленного вызова процедур, независимого от сети, основные шаги работы с ним и назначение. Сравнение распределенных и нераспределенных Java программ. Уровни архитектуры, заглушки и скелета, удаленных ссылок и транспорта Java RMI.

    лабораторная работа [24,6 K], добавлен 30.06.2009

  • Анализ игровых жанров для мобильных устройств и целевой аудитории. Разработка концепции игрового приложения, основной механики, меню и интерфейса игры. Описание переменных скриптов. Реализация выбора цели и стрельбы. Настройка работоспособности игры.

    дипломная работа [1,4 M], добавлен 19.01.2017

  • Программный продукт для игры "Крестики-нолики". Описание пользовательского интерфейса. Факт базы данных, определяющий состояние счёта. Предикат изменяющий состояние игрового процесса и подсчитывающий количество занятых ячеек поля. Исходный код программы.

    курсовая работа [34,6 K], добавлен 19.05.2014

  • Функция протокола и структура пакета разрабатываемого протокола. Длина полей заголовка. Расчет длины буфера на приеме в зависимости от длины пакета и допустимой задержки. Алгоритмы обработки данных на приеме и передаче. Программная реализация протокола.

    курсовая работа [1,0 M], добавлен 18.05.2014

  • Разработка игрового проекта на игровом движке Unity 3D в среде программирования MS Visual Studio 2017. Блок-схема алгоритма работы приема сообщений с сервера на клиенте с упрощенным описанием выполняемых команд. Реализация пользовательского интерфейса.

    курсовая работа [1,5 M], добавлен 10.07.2017

  • Общая характеристика сетевой игры с несколькими клиентами в программной среде MS Visual Studio 2010 на языке программирования C++ с использованием функций работы с сокетами. Реализация системного сервиса, разработки интерфейса, алгоритм его тестирования.

    курсовая работа [495,3 K], добавлен 06.01.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.