Проектирование, реализация и тестирование сетевого приложения, реализующего игру 'Двадцать одно'

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    315,38 Кб
  • Опубликовано:
    2013-01-03
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Проектирование, реализация и тестирование сетевого приложения, реализующего игру 'Двадцать одно'














Проектирование, реализация и тестирование сетевого приложения, реализующего игру "Двадцать одно"

ВВЕДЕНИЕ

сетевая игра программирование

Цель данной курсовой работы состоит в проектировании, реализации и тестирования сетевого приложения, реализующего игру “Двадцать одно”.

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

В игре, не считая дилера, могут участвовать от одного и более игроков. В рассматриваемом варианте игры максимальное количество игроков равняется девяти. Колода, используемая при игре в двадцать одно, насчитывает 52 карты. Однако для усложнения игры обычно применяется сразу несколько колод (так называемый «шуз»), карты в которых могут перемешиваться перед каждой партией. Обычно используют 6 колод.

Достоинства карт: от двойки до десятки - соответственно от 2 до 10 очков, валет - 2 очка, дама - 3, король - 4, туз - 1 или 11.

Целью игры является набрать больше очков, чем дилер. При равном количестве очков побеждает дилер.

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

Игра заканчивается после того как все игроки набрали необходимое количество карт (тогда победитель определяется простым подсчетом очков).

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

В данной курсовой в качестве языка программирования будет использоваться C++ с WinAPI 32.

1. АНАЛИЗ ИСХОДНЫХ ДАННЫХ

.1       Характеристика требований на разработку

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

Так же в рамках курсового проекта должна быть разработана следующая документация:

1. диаграмма классов (представлена в приложении А);

. диаграмма прецедентов (представлена в приложении Б);

. диаграмма компонентов (представлена в приложении В);

. диаграмма развёртывания (представлена в приложении Г);

.2       Анализ предметной области

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

.3       Специальное и общесистемное программное обеспечение

Согласно исходным данным средой разработки проекта будет являться MS Visual Studio 2010. Данная среда программирования была выбрана исходя из задания к курсовому проекту. Visual Studio, в первую очередь, считается универсальной и многофункциональной средой программирования. Согласно техническому заданию разработка должна вестись на языке программирования C++ с использованием функций работы с сокетами.

2. ПРОЕКТИРОВАНИЕ ПРИЛОЖЕНИЯ

.1 API функции сетевого взаимодействия (Winsock2 API)

В операционной системе Windows доступ к API сокетов осуществляется через библиотеку Winsock2. В исходном коде программы достаточно включить один заголовочный файл winsock2.h и все функции для работы с сетевой подсистемой станут доступными в программе.

Сокет - это конечная точка сетевых коммуникаций. Он является неким абстрактным буфером, который может отправлять и принимать данные, пряча от программиста подробности конкретной реализации сетевой подсистемы. В программе сокет идентифицируется дескриптором - обычно это переменная типа int, хранящая ссылку на некий объект в ядре операционной системы, который и осуществляет реальную работу по отправке/приму данных. Программа получает дескриптор от операционной системы при создании сокета, а затем передаёт его функциям Winsock API для указания объекта ядра, над которым необходимо выполнить то или иное действие.

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

#include <Winsock2.h>

int socket(int domain, int type, int protocol);

Домен определяет пространство адресов, в котором располагается сокет, и множество протоколов, которые используются для передачи данных. Чаще других используется домен Internet, задаваемый константой AF_INET (префикс AF означает "address family" - "семейство адресов"). Сокеты, размещённые в этом домене, могут использоваться для работы в любой IP-сети. Тип сокета определяет способ передачи данных по сети. Наконец, последний атрибут определяет протокол, используемый для передачи данных. Часто протокол однозначно определяется по домену и типу сокета. В этом случае в качестве третьего параметра функции socket можно передать 0, что соответствует протоколу по умолчанию. Тем не менее, иногда (например, при работе с низкоуровневыми сокетами) требуется задать протокол явно. Числовые идентификаторы протоколов зависят от выбранного домена; их можно найти в документации.

Прежде чем передавать данные через сокет, его необходимо связать с адресом в выбранном домене (эту процедуру называют именованием сокета). Иногда связывание осуществляется неявно (внутри функций connect и accept), но выполнять его необходимо во всех случаях. Вид адреса зависит от выбранного вами домена. В Unix-домене это текстовая строка - имя файла, через который происходит обмен данными. В Internet-домене адрес задаётся комбинацией IP-адреса и 16-битного номера порта. IP-адрес определяет хост в сети, а порт - конкретный сокет на этом хосте. Протоколы TCP и UDP используют различные пространства портов.

Для явного связывания сокета с некоторым адресом используется функция bind. Её прототип имеет вид:

bind(int sockfd, struct sockaddr *addr, int addrlen);

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

Установка соединения на стороне сервера состоит из четырёх этапов. Сначала сокет создаётся и привязывается к локальному адресу. Если компьютер имеет несколько сетевых интерфейсов с различными IP-адресами, то можно принимать соединения только с одного из них, передав его адрес функции bind. Если же есть потребность соединяться с клиентами через любой интерфейс, необходимо задать в качестве адреса константу INADDR_ANY. Что касается номера порта, то можно задать конкретный номер или 0 (в этом случае система сама выберет произвольный неиспользуемый в данный момент номер порта).

На следующем шаге создаётся очередь запросов на соединение. При этом сокет переводится в режим ожидания запросов со стороны клиентов. Всё это выполняет функция

listen(int sockfd, int backlog);

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

int accept(int sockfd, void *addr, int *addrlen);

Функция accept создаёт для общения с клиентом новый сокет и возвращает его дескриптор. Параметр sockfd задаёт слушающий сокет. После вызова он остаётся в слушающем состоянии и может принимать другие соединения. В структуру, на которую ссылается addr, записывается адрес сокета клиента, который установил соединение с сервером. В переменную, адресуемую указателем addrlen, изначально записывается размер структуры; функция accept записывает туда длину, которая реально была использована.

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

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

Здесь sockfd - сокет, который будет использоваться для обмена данными с сервером, serv_addr содержит указатель на структуру с адресом сервера, а addrlen - длину этой структуры.

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

Функция send используется для отправки данных и имеет следующий прототип

int send(int sockfd, const void *msg, int len, int flags);

Здесь sockfd - это дескриптор сокета, через который отправляются данные, msg - указатель на буфер с данными, len - длина буфера в байтах, а flags - набор битовых флагов, управляющих работой функции (если флаги не используются, передается 0).

Для чтения данных из сокета используется функция

int recv(int sockfd, void *buf, int len, int flags);

Её использование аналогично send. По аналогии с send функция recv возвращает количество прочитанных байтов, которое может быть меньше размера буфера. Существует особый случай, при котором recv возвращает 0. Это означает, что соединение было разорвано.

Закончив обмен данными, необходимо закрыть сокет с помощью функции close. Это приведёт к разрыву соединения и освобождению памяти ядра операционной системы, занятой данным сокетом.

int closesocket(int fd)

2.2 Запуск программы на выполнение в виде службы операционной системы Windows

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

Такая подсистема сервисов позволяет легко устанавливать, запускать, приостанавливать и завершать работу сервисов, централизованно устанавливать зависимости между различными службами, очередность их запуска и так далее.

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

2.3 Варианты использования приложения

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

.        Создание новой игры с указанием количества игроков;

.        Просмотр текущего списка игр на выбранном игровом сервере;

.        Подключение к существующей игре;

.        Выход из игры.

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

Подробно варианты использования приложения представлены в приложении А.

3. РЕАЛИЗАЦИЯ ПРИЛОЖЕНИЯ И ТЕСТИРОВАНИЕ

.1 Особенности реализации

Алгоритм функционирования приложения представлен ниже.

Запуск сервера осуществляется в виде службы операционной системы Windows. Для этого запускается исполняемый файл 21(SERVER).exe с соответствующими параметрами командной строки.


.2 Реализация системного сервиса

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

21(SERVER).exe -i

для инсталляции сервиса в системе и

(SERVER).exe -u

для деинсталляции сервиса.

Данные действия осуществляются при помощи функций InstallService() и UninstallService() соответственно. Листинг данных функций приведен ниже:

void InstallServer()

{_HANDLE scm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);(scm == NULL) {

                   return -1;

}_HANDLE srvc = CreateService(scm, NAME_OF_SERVICE, NAME_OF_SERVICE_LONG, SC_MANAGER_ALL_ACCESS,_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,, NULL, NULL, NULL, NULL, ""

);(srvc == NULL) {

                   return -1;

}(srvc);(scm);

}

UninstallServer()

{_HANDLE scm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);(scm == NULL) {

                   return -1;

}_HANDLE srvc = OpenService(scm, NAME_OF_SERVICE, SC_MANAGER_ALL_ACCESS);(srvc == NULL) {

                   return -1;

}_STATUS ss;(!QueryServiceStatus(srvc, &ss))

{

                   return -1;

}(ss.dwCurrentState != SERVICE_STOPPED)(!ControlService(srvc, SERVICE_CONTROL_STOP, &ss)) {

                   return -1;

}(!DeleteService(srvc)) {

                   return -1;

}

CloseServiceHandle(srvc);

CloseServiceHandle(scm);

}

При запуске сервиса стартует поток StreamServer(LPVOID lpParam), который осуществляет создание и прослушивание серверного сокета в ожидании новых клиентских подключений. Сразу же после успешного выполнения функции accept для вновь подключившегося клиента осуществляется создание нового потока ClientThread(LPVOID lpParam), который и осуществляет непосредственное исполнение команд клиента.

Данные о конкретной игре содержатся в объекте класса Table.

Синхронизация осуществляется с помощью механизма «критических секций» операционной системы Windows.

При обмене данными с клиентом для каждой карты используется особая кодировка: каждая карта в колоде пронумерована от 0 до 51. Начиная от двойки до туза. Последовательность мастей следующая: крести, бубны, черви, пики.

Ниже приведен листинг функции, осуществляющей генерацию карты из карточной колоды для шуза.

int Table::genCard(){

         int count=0;

         for(int i=0; i<52*6; i++){

                   if(cards[i] == true)

                            count++;

         }

         int w = time(NULL);

         int temp=((rand()+(52*6)+time(NULL))%count)+1;

         for(int i=0; i<52*6; i++){

                   if(cards[i] == true)

                            temp--;

                   if(temp==0){

                            cards[i] = false;

                            return (i%52);

                   }

         }

}

Подробнее взаимосвязи между различными классами серверной части приложения представлены в приложении Б.

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

.3 Реализация клиентской части

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

Главное окно программы представлено на рисунке 3.3.1.

Рисунок 3.3.1 - Главное окно приложения

Создание новой игры осуществляется командой меню Игра -> Новый стол. При этом будет отображено диалоговое окно создаваемого стола, оно изображено на рисунке 3.3.2.

В первом поле нужно ввести название стола. Во втором максимальное количество игроков от 1 до 9.

Рисунок 3.3.2 - Диалоговое окно «Новый стол»

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

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

В нижней части окна находится поля для ввода ip адреса сервера и номера порта. Кнопка «+» осуществляет подключение.

Рисунок 3.3.3 - Диалоговое окно выбора стола

Для выбора стола игрок должен дважды кликнуть левой кнопкой мыши на необходимый стол. После этого игрок перейдёт на данный стол, в качестве зрителя. Игровой стол изображён на рисунке 3.3.4.

Рисунок 3.3.4 - Изображение игрового стола

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

Рисунок 3.3.5 - Игровое поле после раздачи начальных карт

Игрок, обладающий правом хода, может взять еще одну карту при помощи нажатия кнопки «Еще» или же спасовать, если у него достаточное количество карт при помощи нажатия кнопки «Хватит». Причем, данные кнопки доступны пользователю только в то время, когда данный игрок обладает правом хода.

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

При выигрыше или проигрыше игроку будет выведено соответствующее сообщение и игра будет закончена.

.4 Тестирование приложения

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

Порядок испытаний имеет следующий вид:

-    Регистрация сервиса сервера, убедиться в корректности регистрации;

-       Старт сервера как сервис, убедиться в корректности старта;

-       Останов сервиса, убедиться в корректности останова;

-       Удаление сервиса, убедиться в корректности удаления;

-       Подключение к серверу, убедиться в корректности подключения;

-       Создание новой игры;

-       Вывод списка существующих игр;

-       Подключение к существующей игре;

-       Переход хода, убедиться в корректности перехода;

-       Раздача карт, убедиться в корректности раздачи;

-       Завершение игры, убедиться в корректности игры;

-       Отключение от сервера, убедиться в корректности отключения.

Результаты тестирования работоспособности проведенного в соответствии с порядком испытаний приведены в таблице 3.4.1.

Таблица 3.4.1 - Протокол тестирования приложения

Функция

Результат тестирования

Регистрация сервиса сервера

работает

Старт сервера как сервис

работает

Останов сервиса

работает

Удаление сервиса

работает

Подключение к серверу

работает

Создание новой игры

работает

Старт игры

работает

Вывод списка существующих игр

работает

Подключение к существующей игре

работает

Переход хода

работает

Раздача карт

работает

Завершение игры

работает

Отключение от сервера

работает


ЗАКЛЮЧЕНИЕ

В результате выполнения курсового проекта было разработана сетевая карточная игра «Двадцать одно». Интерфейс программы удобен и понятен для широкого круга пользователей.

Разработанное приложение соответствует всем требованиям, предъявленным в техническом задании.

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

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

1.       Гордеев А.В., Молчанов А.Ю. Системное программное обеспечение - СПб.: Питер, 2002 - 736с.

.        Юрий Щупак. Win32 API. Разработка приложений для Windows - СПб.: Питер, 2008 - 592с.

ПРИЛОЖЕНИЯ

Приложение А (обязательное)

диаграмма классов


Приложение Б (обязательное)

диаграмма прецедентов


Приложение В (обязательное)

UML диаграмма компонентов


Приложение Г (обязательное)


Похожие работы на - Проектирование, реализация и тестирование сетевого приложения, реализующего игру 'Двадцать одно'

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!