Лабораторная работа № 9. Компьютерные игры. Морской бой
Цель работы: Получение навыков работы с протоколом TCP/IP, программирования сокетов, написание собственного протокола прикладного уровня OSI.
Теоретическая справка.
Компонента ServerSocket Сервер, основанный на сокетном протоколе, позволяет обслуживать сразу множество клиентов. Для каждого подключенного клиента сервер открывает отдельный сокет, по которому можно обмениваться данными с клиентом. Также возможно создание для каждого подключения отдельного процесса.
Определение свойств Port и ServerType необходимо, чтобы к серверу могли подключаться клиенты, нужно, чтобы порт, используемый сервером точно совпадал с портом, используемым клиентом (и наоборот). Свойство ServerType определяет тип подключения.
На этапе открытия сокета и указанного порта может выполняться автоматическое начало ожидания подсоединения клиентов (Listen).
При отключении клиента закрывается его сокетное соединение с сервером.
По команде приложения сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.
Свойство ServerType:TServerType указывает тип сервера. Оно может принимать одно из двух значений: stNonBlocking - синхронная работа с клиентскими сокетами. При таком типе сервера можно работать с клиентами через события OnClientRead и OnClientWrite. StThreadBlocking - асинхронный тип. Для каждого клиентского сокетного канала создается отдельный процесс (Thread).
Свойство Active: Boolean - показатель того, активен в данных момент сервер, или нет. Значение True указывает на то, что сервер работает и готов к приему клиентов, а False - сервер выключен. Чтобы запустить сервер, нужно просто присвоить этому свойству значение True.
Port: Integer это номер порта для установления соединений с клиентами. Значение порта у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535, т.к. от 1 до 1024 - могут быть заняты системой /2/.
Метод Open запускает сервер. Эта команда идентична присвоению значения True свойству Active.
Метод Close останавливает сервер.
Событие OnClientConnect возникает, когда клиент установил сокетное соединение и ждет ответа сервера (OnAccept).
Событие OnClientDisconnect возникает, когда клиент отсоединился от сокетного канала.
Событие OnClientError возникает, когда текущая операция завершилась неудачно, т.е. произошла ошибка.
Событие OnClientRead возникает, когда клиент передал серверу какие-либо данные. Доступ к этим данным можно получить через передаваемый параметр Socket: TCustomWinSocket.
Событие OnClientWrite возникает, когда сервер может отправлять данные клиенту по сокету.
Событие OnAccept возникает, когда сервер принимает клиента или отказывает ему в соединении;
Событие OnListen возникает, когда сервер переходит в режим ожидания подсоединения клиентов.
Компонента ClientSocket.
После назначения свойствам Host и Port соответствующих значений, можно приступить непосредственно к открытию сокета (сокет здесь рассматривается как очередь, в которой содержатся символы, передающиеся от одного компьютера к другому). Для этого можно вызвать метод Open компонента TClientSocket, либо присвоить свойству Active значение True /2/.
Этап авторизации необходим, если сервер требует ввода логина и/или пароля. На этом этапе посылается серверу логин (имя пользователя) и пароль. Механизм авторизации зависит уже от конкретного сервера.
Свойство Host: string это строка, указывающая на хост-имя компьютера, к которому следует подключиться.
Address: string - строка, указывающая на IP-адрес компьютера, к которому следует подключиться. В отличие от Host, здесь может содержаться лишь IP. Отличие в том, что при указании в Host символьного имя компьютера, IP адрес, соответствующий этому имени, будет запрошен у DNS.
Строка Service : string, определяет службу (ftp, http, pop, и т.д.), к порту которой произойдет подключение. Это своеобразный справочник соответствия номеров портов различным стандартным протоколам.
Свойство ClientType это тип соединения. CtNonBlocking - асинхронная передача данных, т.е. посылать и принимать данные по сокету можно с помощью OnRead и OnWrite. CtBlocking - синхронная (одновременная) передача данных. События OnRead и OnWrite не работают. Этот тип соединения полезен для организации обмена данными с помощью потоков.
Событие OnConnect возникает при установлении соединения. Т.е. в обработчике этого события уже можно начинать авторизацию или прием/передачу данных /2/.
Событие OnConnecting возникает при установлении соединения. Отличие от OnConnect в том, что соединение еще не установлено. Обычно такие промежуточные события используются для обновления статуса.
Событие OnDisconnect возникает при закрытии сокета.
Событие OnError возникает при ошибке в работе сокета. Следует отметить, что это событие не поможет отловить ошибку в момент открытия сокета (Open). Для того, чтобы избежать выдачи сообщения об ошибке, необходимо заключить операторы открытия сокета в блок try..except (обработка исключительных ситуаций).
Событие OnLookup возникает при попытке получения от DNS IP-адреса указанного хоста.
Событие OnRead возникает, когда удаленный компьютер послал какие-либо данные. При возникновении этого события возможна обработка данных.
Событие OnWrite возникает, когда разрешена запись данных в сокет.
Метод SendBuf(var Buf; Count: Integer) используется при посылке буфера через сокет. Буфером может являться любой тип, будь то структура (record), либо простая переменная типа Integer. Буфер указывается параметром Buf, вторым параметром необходимо указать размер пересылаемых данных в байтах (Count).
Метод SendText(const S: string) используется при посылке текстовой строки через сокет.
SendStream(AStream: TStream) это посылка содержимого указанного потока через сокет. Пересылаемый поток должен быть открыт. Поток может быть любого типа – файловый или из оперативной памяти /2/.
Ход работы:
1. Установить сетевое соединение двух компьютеров.
2. Подготовка к игре. Каждый из игроков расставляет на игровом поле (10х10 клеток) корабли (четыре корабля размером в одну клетку, три – размером в две, два корабля – в три клетки и один корабль - 4 клетки (рисунок 19) , в соответствии с правилами игры (корабли не должны располагаться на смежных клетках).
Рисунок 19 – Размещение кораблей на игровом поле
3. Игра. На основе договоренности первого хода (т.е. заранее решено, кто будет делать первый ход: «сервер» или «клиент») игрок №1 делает первый ход – посылает запрос о какой-либо клетке игрового поля на предмет наличия в ней корабля противника. Приложение оппонента (игрок №2) обрабатывает запрос и посылает данные обратно игроку №1. В присланных данных может содержаться два типа сообщения: либо в данной клетке есть корабль (т.е. «попал» или «убил» - в этом случае игрок №1 ходит еще раз и данная клетка помечается «крестиком»), либо в данной клетке нет корабля (т.е. «мимо» - в этом случае игрок №1 теряет право хода и передает ход игроку №2. Игрок №2 посылает аналогичный запрос игроку №1 (рисунок 20).
Рисунок 20 - Игра
Игра заканчивается в том случае, когда «потоплены» корабли одного из игроков.
4. Выход из программы или новая игра (возврат к пункту 2).
Оформление работы.
Отчет по лабораторной работе должен содержать:
- название и цель работы;
- руководство для пользователя программы;
- руководство для программиста;
- алгоритм программы;
- листинг программы;
- экранные формы работы программы;
- вывод по выполненной работе;
- список использованных источников.
Контрольные вопросы:
- перечислите методы и опишите их характерные особенности, которые используются сокетами для передачи данных между компьютерами?;
- какие компоненты использовались при построении программы?;
- в каком виде передаются данные через сокеты?;
стек TCP/IP?;
модель OSI?.