Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming / GameProg / RPG_Programming_2ed.pdf
Скачиваний:
240
Добавлен:
12.02.2016
Размер:
12.06 Mб
Скачать

Глава 5. Работа с сетью с DirectPlay

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

typedef HRESULT (WINAPI *PFNDPNMESSAGEHANDLER)(

PVOID pvUserContext, // Предоставляемый приложением указатель

DWORD

dwMessageType,

//

Тип полученного сообщения

PVOID

pMessage);

//

Буфер с зависящими от сообщения данными

Переменная pvUserContext — это указатель на какие-либо данные,

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

состояние игры, или любую другую информацию по вашему желанию. Аргументы dwMessageType и pMessage относятся к сообщениям, и вы

узнаете о них в разделе «Получение данных» далее в этой главе.

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

HRESULT IDirectPlay8Server::Initialize(

PVOID const

pvUserContext,

//

Предоставляемый пользователем

const

 

 

//

указатель

PFDNPMESSAGEHANDLER pfn, //

Функция обратного вызова

const

DWORD

dwFlags);

//

для обработки сообщений

//

0

ПРИМЕЧАНИЕ

Функция Initialize (с теми же самыми параметрами)

 

работает в каждой из моделей:

 

HRESULT

IDirectPlay8Client::Initialize(...);

 

HRESULT

IDirectPlay8Peer::Initialize(...);

Вот пример создания вашей собственной функции обратного вызова (сейчас это только прототип) и инициализации только что созданного сетевого объекта сервера:

// Прототип функции обратного вызова

HRESULT WINAPI MessageHandler(PVOID pvUserContext,

DWORD dwMessageId, PVOID pMsgBuffer);

// Инициализация ранее созданного объекта pDPServer if(FAILED(pDPServer->Initialize(NULL, MessageHandler, 0))) {

// Произошла ошибка

}

Вот и все, что относится к созданию и инициализации сетевых объектов. Следующий этап — создание объекта адреса.

Использование адресов

Как вы уже читали, в сети для доставки данных используется IP-адрес и

номер порта. В DirectPlay вы конструируете этот адрес в его собственном объекте IDirectPlay8Address. Объект адреса предоставляет для

266

netlib.narod.ru

Джим Адамс

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

Таблица 5.3. Функции IDirectPlay8Address

Функция

Описание

 

 

IDirectPlay8Address::Clear

Очищает все данные адреса.

IDirectPlay8Address::SetSP

Устанавливает поставщика услуг.

IDirectPlay8Address::AddComponent

Добавляет компоненты адреса.

Инициализация объекта адреса

Перед тем, как вы сможете использовать объект адреса, необходимо создать его с помощью показанной ранее функции CoCreateInstance:

IDirectPlay8Address *pDPAddress;

if(FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC, IID_IDirectPlay8Address, (void**)&pDPAddress))) {

// Произошла ошибка

}

Добавление компонентов

Объект адреса просто содержит строку в формате Unicode. Эта строка содержит название поставщика услуг, номер порта, и другую информацию. Его единственное назначение — построить эту строку, которую будут использовать другие объекты.

Чтобы добавить компонент к объекту адреса используйте функцию

IDirectPlay8Address::AddComponent:

HRESULT IDirectPlay8Address::AddComponent(

const WCHAR

*const

pwszName,

// Имя устанавливаемого компонента

const void

*const

lpvData,

// Буфер,

содержащий устанавливаемую

const

DWORD

dwDataSize,

// информацию о компоненте

//

Размер

используемого буфера данных

const

DWORD

dwDataType);

//

Тип используемых данных

Эта небольшая функция требует большого количества пояснений, так что давайте приостановимся. Первый аргумент, pwszName, — это указатель

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

Какой буфер передавать функции AddComponent через аргумент lpvData зависит от типа передаваемого компонента, но обычно это строка

(Unicode или ANSI), двойное слово (DWORD), GUID или двоичные данные.

netlib.narod.ru

267

Глава 5. Работа с сетью с DirectPlay

Тип передаваемых данных сообщает параметр dwDataType, в котором можно использовать один из макросов, перечисленных в таблице 5.5.

Таблица 5.4. Макросы для имен компонентов

Компонент

Макрос

Поставщик Сетевое устройство Номер порта Имя/адрес узла Номер телефона Скорость передачи Контроль потока Четность Стоп-биты

DPNA_KEY_PROVIDER DPNA_KEY_DEVICE DPNA_KEY_PORT DPNA_KEY_HOSTNAME DPNA_KEY_PHONENUMBER

DPNA_KEY_BAUD

DPNA_KEY_FLOWCONTROL DPNA_KEY_PARITY DPNA_KEY_STOPBITS

Таблица 5.5. Типы данных компонентов

Тип

Макрос

 

 

Строка (Unicode)

DPNA_DATATYPE_STRING

 

Строка (ANSI)

DPNA_DATATYPE_STRING_ANSI

DWORD

DPNA_DATATYPE_DWORD

GUID

DPNA_DATATYPE_GUID

Двоичные данные

DPNA_DATATYPE_BINARY

 

Последний аргумент, dwDataSize, определяет размер отправляемых

данных (DWORD,

длину строки, размер GUID и т.д.). Достаточно трудно

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

Рис. 5.7. Объект адреса содержит информацию из различных компонентов. Каждому компоненту соответствует его тип данных

268

netlib.narod.ru

Джим Адамс

Установка поставщика услуг

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

параметр, для установки которого не используется функция AddComponent. Вместо нее применяется функция

IDirectPlay8Address::SetSP:

HRESULT IDirectPlay8Address::SetSP(

const GUID *const pguidSP); // GUID поставщика услуг

GUID каждого поставщика услуг приведен в таблице 5.6. Выбор зависит

от вас, но в этой книге я использую только поставщика услуг TCP/IP (CLSID_DP8SP_TCPIP).

Таблица 5.6. Поставщики услуг DirectPlay

Тип

GUID

 

 

TCP/IP

CLSID_DP8SP_TCPIP

IPX

CLSID_DP8SP_IPX

Модем

CLSID_DP8SP_MODEM

Последовательный порт

CLSID_DP8SP_SERIAL

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

// Установка поставщика услуг TCP/IP if(FAILED(pDPAddress->SetSP(&CLSID_DP8SP_TCPIP))) {

// Произошла ошибка

}

Выбор порта

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

ПРИМЕЧАНИЕ

Номер используемого порта можно выбирать, но не стоит

 

использовать зарезервированные значения (от 1 до 1024).

 

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

 

1024.

 

Вы можете делегировать выбор порта DirectPlay, указав в

 

номере порта 0, но тогда номер порта может быть любым и

 

вам придется запрашивать его. Предпочтительнее самому

 

выбирать порт.

 

 

Вы устанавливаете порт, используя функцию

IDirectPlay8Address::AddComponent. Хотя, как я уже говорил,

netlib.narod.ru

269

Соседние файлы в папке GameProg