ГЛАВА 8. ТЕХНОЛОГИИ ОБМЕНА ИНФОРМАЦИЕЙ В ОС WINDOWS 4 глава




пользоваться она может как клиентами, так и серверами, хотя для первых она более по-

лезна.

 

BOOL TransactNamedPipe(


HANDLE hNamedPipe,

LPVOID lpvWriteBuf,


// дескриптор именованного канала

// буфер для хранения передаваемой

 



 

DWORD dwWriteBufSize,

LPVOID lpvReadBuf,

DWORD dwReadBufSize,

LPDWORD lpdwBytesRead,

байтов


 

 

// информации

// размер буфера записи, байты

// буфер для полученной информации

// размер буфера чтения, байты

// реально прочитанное количество

 

// (возвращаемое значение)


LPOVERLAPPED lpOverlapped); // поддержка асинхронного ввода/вывода

 

Несмотря на обилие параметров, функция TransactNamedPipe() действует доста-

точно "прямолинейно". Она записывает в канал содержимое буфера lpvWriteBuf, ожида-

ет ответа и копирует полученное сообщение в буфер lpvReadBuf.

Функция TransactNamedPipe() выдает сообщение об ошибке в том случае, если ка-

нал имеет неправильные атрибуты или если буфер чтения слишком мал для размещения

всего принятого сообщения. При этом функция GetLastError() возвращает значение ER-

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

ReadFile() или PeekNamedPipe().

Функция TransactNamedPipe() осуществляет одну операцию обмена информацией

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

раз, не разрывая связи.

Функция CallNamedPipe() предназначена для тех клиентов, которые должны вы-

полнить однократную транзакцию. Она устанавливает соединение, читает информацию

из канала и записывает ее в канал, после чего разрывает связь.

 

BOOL CallNamedPipe(


LPTSTR lpszPipeName,

LPVOID lpvWriteBuf,

DWORD dwWriteBuf,

LPVOID lpvReadBuf,

DWORD dwReadBuf,

LPDWORD lpdwRead,

 

DWORD dwTimeout);


// указатель строки с именем объекта-канала

// буфер для хранения передаваемой информации

// размер буфера записи, байты

// буфер для хранения принимаемой информации

// размер буфера чтения, байты

// реально прочитанное количество байтов

// (возвращаемое значение)

// максимальное время ожидания, миллисекунды


 

В качестве первогопараметра функции CallNamedPipe() должно задаваться имя

уже существующего канала. Данная функция может вызываться только клиентами. Ос-

тальные параметры, точнее большая их часть, описывают буферы, необходимые для

двухсторонней поддержки транзакции.

Функция CallNamedPipe() комбинирует в одной операции несколько команд, а

именно:WaitNamedPipe(), CreateFile(), WriteFile(), ReadFile() и CloseHandle(). Последний

параметр, dwTimeout, задает максимальное время ожидания для команды WaitNamed-

Pipe().

Если буфер чтения слишком мал для записи всего принятого сообщения, функция

считывает максимально возможный объем информации и возвращает значение FALSE.

В этом случае функция GetLastError() возвращает значение ERROR_MORE_DATA, и

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

Клиенты часто посылают серверу по каналу команды или запросы на выполнение

определенных действийотсвоегоимени. Так, клиент может попросить сервер прочи-

тать информацию из файла. Поскольку клиент и сервер - это разные процессы, часто они

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

прав на выполнение которых у клиента недостаточно. Сервер может временно (на время

 

 



 

 

выполнения запроса) присвоить себе атрибуты безопасности клиента, а затем восстано-

вить собственные атрибуты с помощью следующих функций:

 

BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe);

BOOL RevertToSelf(void);

 

Функция ImpersonateNamedPipeClient() не работает с анонимными каналами и не

позволяет серверу принимать полномочия клиента с удаленного компьютера. К тому же

она временно изменяет контекст безопасности вызывающего потока

Функция RevertToSelf() завершает процесс передачи полномочий и восстанавлива-

ет исходный контекст безопасности.

Клиент разрываетсвязьсканалом посредством вызова функции CloseHandle().

Сервер может поступить таким же образом, однако иногда предпочтительнее отклю-

читься от клиента, не уничтожая канал (это позволит сохранить его для использования в

будущем). С помощью функции DisconnectNamedPipe() сервер в принудительном по-

рядке прекращает диалог с клиентом и делает его дескриптор недействительным.

 

BOOL DisconnectNamedPipe(HANDLE hNamedPipe);

 

Если клиент попытается выполнить чтение или запись с помощью своего дескрип-

тора после отключения сервера, возникнет ошибка, и ему все равно придется вызвать

функцию CloseHandle().

В результате разрыва соединения все данные, оставшиеся в канале, будут утеряны.

Сервер может сохранить оставшуюся информацию, вызвав функцию FlushFileBuffers().

 

BOOL FlushFileBuffers (HANDLE hFile);

 

Получив дескриптор именованного канала, функция FlushFileBuffers() блокируется

до тех пор, пока не освободятся буферы этого канала.

При отключении канала от клиента сам объект-канал не уничтожается. Разорвав

соединение, сервер должен вызвать функцию ConnectNamedPipe() в ожидании нового

подключения освободившегося канала или же вызвать функцию CloseHandle() для унич-

тожения данного экземпляра объекта. Клиенты, заблокированные функцией WaitNa-

medPipe(), при закрытии своего дескриптора канала разблокированы не будут. Ожидая

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

функцию ConnectNamedPipe().

Таким образом, как и большинство из рассмотренных до сих пор объектов, каналы

остаются в памяти до тех пор, пока не будут закрыты все их дескрипторы. Любой про-

цесс должен на своем конце канала завершаться вызовом функции CloseHandle(). Если

вы забудете об этом, команда ExitProcess() автоматически закроет все оставшиеся деск-

рипторы.

 

§ 8.3.Обменинформациейсиспользованиемсокетов

 

8.3.1. Общие положения. Виды сетевых протоколов

 

Для разработки программного обеспечения для сетевых технологий необходимо

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

этому вначале рассмотрим некоторые общие вопросы. Большинство начинающих поль-

зователей Internet быстро привыкают к тому факту, что у них есть свой адрес электрон-

ной почты и IP-адрес. Настройка компьютера для работы в сетях TCP/IP обычно

 

 


 

 

подразумевает указание IP-адресов для доменного имени сервера и сетевого шлюза, а

также ввод серверных имен POP и SMTP. IP-адреса задаются в виде четырехразрядной

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

числом и отделен точкой от соседнего байта. Такая система обозначений принята для

упрощения восприятия IP-адресов человеком. Компьютеры и другое аппаратное обеспе-

чение Internet всегда воспринимают 4-байтовые (32-разрядные) значения непосредст-

венно.

Поскольку каждый компьютер в Internet имеет собственный IP-адрес (по крайней

мере, пока он подключен к сети), а число таких компьютеров увеличивается неудержимо

быстрыми темпами, ведутся работы по внедрению новой схемы адресации. Однако ре-

шение возникающих при этом проблем связано с определенными трудностями, поэтому

в ближайшее время мы будем пользоваться в своих программах 32-разрядными IP-

адресами. Рассмотрим основные Internet-протоколы.

TCP/IP - это набор связанных протоколов, соответствующих разным уровням мо-

дели OSI. (Например, на нижних уровнях расположены основные пакетные протоколы

TCP и UDP, обеспечивающие транспортировку данных методом последовательной дву-

направленной передачи или методом однонаправленной передачи без установления со-

единения.)

Протокол IP (Internet Protocol) выполняет в Internet роль "службы доставки",

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

передаваемые без установления соединения, поэтому IP-пакеты часто называют IР-

дейтаграммами.

Протокол TCP (Transmission Control Protocol) представляет собой последователь-

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

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

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

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

Протокол UDP (User Datagram Protocol), в отличие от TCP, считается "ненадеж-

ным", так как осуществляет передачу пакетов данных без установления соединения и,

следовательно, не способен реализовать проверку контрольных сумм. Данный протокол

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

жете проверить, принят ли он.

Два описанных подхода взаимно дополняют друг друга. Передача данных без ус-

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

редачи и приема не проверятся. Протокол TCP требует дополнительных расходов, но

обеспечивает корректную передачу данных по месту назначения и устраняет ошибки,

происходящие в каких-либо звеньях аппаратного обеспечения сети (в кабелях, в комму-

тирующих устройствах и т.д.).

Высший уровень стека TCP/IP содержит протоколы, предназначенные для более

специализированных целей. Эти протоколы выполняют роль различных сетевых серви-

сов и используются для передачи электронной почты, файлов, документов, Web-страниц

и т.д. Перечислим протоколы, которые входят в данную группу.

SMTP (Simple Mail Transfer Protocol) - Используется для отправки электронной почты

на сервер.

РОРЗ (Post Office Protocol 3) - Предназначен для чтения электронной почты с сервера.

FTP (File Transfer Protocol) - Широко применяется для передачи файлов.

HTTP (Hypertext Transfer Protocol) - Используется в качестве стандартного Web-

протокола.

Telnet Предназначен для удаленной регистрации и интерактивного доступа к удаленным

серверам.

 


 

 

В то время как низкоуровневые транспортные протоколы осуществляют передачу

информации с помощью довольно сложных структур и пакетов, протоколы высшего

уровня обычно применяют методику, которая более привычна с точки зрения человека и

удобна для программистов. Эти протоколы имеют ряд общих характеристик [12]:

• устанавливают диалог между клиентом и сервером посредством двунаправленного

гнезда;

• применяют числовые коды ответов;

• их пакеты начинаются с распознаваемой командной строки, состоящей из четырех

символов.

Большинство программ, предназначенных для работы с Internet, используют пара-

дигму "гнезд" (sockets). В старые добрые времена, когда TCP/IP был интегрирован в

операционную систему Unix, появился набор функций, получивший название Берклиев-

ского стандарта гнезд (Berkeley sockets standard). Эти функции позволяют создать гнез-

до, прослушать соединение (на стороне сервера), связать гнездо с заданными сервером и

номером порта (на стороне клиента), а также передать и принять информацию через

гнездо. Таким образом, при взаимодействии клиент - сервер в сети каждого участника

взаимодействия можно рассматривать как конечную точку, которая и называется socket

(или "гнездо").

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

рых версиях Unix может использоваться непосредственно функциями ввода/вывода.

Имеется два типа гнезд, соответствующих протоколам, которые подразумевают или от-

рицают потребность в установлении соединения [1, 12]:

• TCP-гнезда - соединение между гнездом и сервером устанавливается;

• UDP-гнезда - для передачи данных необходимо только указать конечный пункт на-

значения (номер порта по заданному IP-адресу).

Принцип взаимодействия сервера и клиентов следующий. На сервере программа

взаимодействия с клиентами подключается к адресу IP, создает гнездо и находится в

режиме ожидания подключения. Программа клиент тоже создает гнездо и пытается под-

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

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

вере гнездо остается в режиме ожидания подключения следующего клиента. Таким спо-

собом производится взаимодействие сервера и многими клиентами.

В начале 90-х годов консорциумом частных лиц и компаний была предложена

версия функций работы с гнездами для Windows, которая стала называться WinSock. Та-

ким образом, WinSock или Windows socket - это интерфейс API-функций, созданный для

реализации приложений в сети на основе протокола TCP/IP. Обычно эти функции опи-

сываются в библиотеке WSOCK32.DLL.

Интерфейс WinSock несколько отличается от Берклеевского стандарта гнезд, так

как 16-разрядные версии Windows, для которых он первоначально создавался, в отличие

от Unix, не были полноценно многозадачными операционными системами. Необходимо

было предусмотреть асинхронный режим работы функций WinSock для исключения

возможности блокировки системы в момент ожидания ответа. В UNIX можно было про-

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

чить их независимость. Современные версии Windows полноценно многозадачны, по-

этому в них можно использовать обычный Берклеевский стандарт гнезд.

В результате вышесказанного спецификация WinSock разделяет функции интер-

фейса на три типа [1]:

1. Расширения Windows для функций Беркли (Асинхронные функции, которые не

блокируют системы при нахождении в режиме ожидания. Данные функции могут

извещать Windows-приложения о своем завершении, отправляя специальное

сообщение указанному окну. При этом приложение может вызвать функцию, про-

 


 

должить другие операции, а затем проверить код завершения функции в очереди

сообщений.);

2. Функции Беркли (Синхронные функции, производящие блокировку интерфейса в

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

функции WinSock);

3. Информационные функции (получение информации о наименовании доменов,

службах, протоколах Internet).

Существует две версии WinSock

• WinSock 1.1 - поддержка только TCP/IP;

• WinSock 2.0 - поддержка дополнительного программного обеспечения

Интерфейс Winsock 2 имеет следующие преимущества [12]:

• поддерживает различные протоколы;

• позволяет создать быстрый программный код, адаптированный к конкретной конфи-

гурации аппаратного обеспечения;

• является единственным решением при создании серверных программ, для которых

существенными характеристиками (более важными, чем, скажем, время разработки)

являются быстродействие и производительность;

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

Текущая версия Winsock 2 поддерживает большинство функции, заимствованных

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

протокольную поддержку. Хотя интерфейс Winsock чаще всего используется с протоко-

лами TCP/IP, он также поддерживает связь посредством гнезд по некоторым другим

протоколам, в том числе IPX, SPX, Banyan VINES и AppleTalk. В этой лекции будет рас-

смотрено только функционирование TCP/IP, однако имейте в виду, что приложения, ра-

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

лов. Интерфейс Winsock содержит как синхронные, так и асинхронные функции для

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

разования данных и просмотра баз данных. Функции интерфейса Winsock2 описаны в

библиотеке ws2_32.dll.

 

8.3.2. API-функции для работы с сокетами

 

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

табл.8.1. Вместе взятые они представляют собой традиционный набор синхронных

функций (функцийБеркли).

Таблица 8.1


 

 

accept


Функция


Описание

Регистрирует подключение к заданному гнезду


AcceptEx

 

 

bind

closesocket

connect

GetAcceptExSock-

addrs

 

ioctlsocket

 


Регистрирует новое подключение, возвращает локальный и уда-

ленный адрес, а также первый блок данных, отправленный кли-

ентом

Назначает гнезду локальный адрес

Закрывает гнездо

Соединяет гнездо с заданным одноранговым узлом

Анализирует данные, переданные функцией AcceptEx, выделяет

локальный и удаленный адреса, а также первый блок данных,

полученных при соединении

Читает или устанавливает параметры режима работы гнезда

Окончание табл. 8.1

 



 

listen

recv

recvfrom

select

send

sendto

setsockopt

shutdown

socket


 

 

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

Читает данные из заданного гнезда

Читает дейтаграмму и исходный адрес

Определяет статус одного или нескольких гнезд

Посылает данные в заданное (подключенное) гнездо

Посылает данные по адресу назначения

Устанавливает параметры гнезда

Запрещает передачу и/или прием данных через указанное гнездо

Создает гнездо, связанное с заданным провайдером транспорт-

ных услуг


 

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

темный вызов socket() [1, 12].

 

s = socket(domain, type, protocol);

 

где domain - тип протокола. Для протокола IP используется параметр AF_INET (Internet

протоколы);

type - тип подключения. Используется три возможных типа:

Stream socket (SOCK_STREAM) - обеспечивает последовательный, надежный, ори-

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

Datagram socket (SOCK_DGRAM) - поддерживает двусторонний поток данных. Не

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

будут дублироваться. Важной характеристикой данного гнезда является то, что гра-

ницы записи данных предопределены.

Raw socket (SOCK_RAW) - обеспечивает возможность пользовательского доступа к

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

Такие гнезда обычно являются датаграм-ориентированными.

protocol - необязательный параметр, при использовании AF_INET принимает значение

0.

Функция socket создает конечную точку для коммуникаций и возвращает файло-

вый дескриптор, ссылающийся на гнездо, или -1 в случае ошибки. Данный дескриптор

используется в дальнейшем для установления связи.

Для создания гнезда типа stream с протоколом TCP, обеспечивающим коммуника-

ционную поддержку, вызов функции socket должен быть следующим:

 

s = socket(AF_INET, SOCK_STREAM, 0);

 

Гнездо создается без имени. Пока с гнездом не будет связано имя, удаленные про-

цессы не имеют возможности ссылаться на него и, следовательно, на данном гнезде не

может быть получено никаких сообщений. Коммуникационные процессы используют

для данных целей ассоциации. В Internet домене ассоциация складывается из локального

и удаленного адреса и из локального и удаленного порта. В большинстве доменов ассо-

циация должна быть уникальной.

В Internet домене связывание гнезда и имени может быть весьма сложным, но, к

счастью, обычно нет необходимости специально привязывать адрес и номер порта к

гнезду, так как функции connect и send автоматически свяжут данный socket с подходя-

щим адресом, если это не было сделано до их вызова.

Для связывания гнезда с адресом и номером порта используют системный вызов

bind:

 

 



 

 

bind(s, sockaddr, sockaddrlen);

 

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

sockaddr - структура, которая интерпретируется поддерживаемым протоколом (IP - ад-



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-04-02 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: