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




пользовать, открывая соединение на своем конце? Чтобы обойти эту проблему, Win32

разрешает серверу многократно создавать один и тот же канал.

Каждый раз при вызове функции CreateNamedPipe() с одним и тем же именем вы

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

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

ко раз создать один и тот же канал. Он получит несколько различных дескрипторов и

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

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

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

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

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

разорвет связь с одним из предыдущих экземпляров канала.

Параметр dwMaxInstances функции CreateNamedPipe() устанавливает верхний пре-

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

тех пор, пока функция CreateNamedPipe() не возвратит код ошибки. Флаг

PIPE_UNLIMITED_INSTANCES свидетельствует об отсутствии верхнего предела. В

этом случае максимальное число экземпляров ограничивается только системными ре-

сурсами. Значение параметра dwMaxInstances не может превышать значения

PIPE_UNLIMITED_INSTANCES. В файле Winbase.H значение параметра dwMaxIns-

tances задано равным 255.

Параметры dwOutBuf и dwInBuf задают начальные размеры буферов, в которые

производится запись информации. Для выходного канала (PIPE_ACCESS_OUTBOUND)

значение имеет только размер выходного буфера, для входного канала - только размер

входного буфера.

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

ния или записи заставляет операционную систему выделить место для буфера из дина-

мической области системной памяти ядра. Значение, определяющее размер буфера, ин-

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

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

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

ректно. Но даже если размер созданного буфера не укладывается в заданные рамки, сис-

тема все равно выделяет для него место - за счет ресурсов процесса. Во избежание пере-

грузки ресурсов процесса каждая операция WriteFile(), вызывающая превышение

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

тех пор, пока поток-получатель не уменьшит объем буфера, прочитав из него достаточ-

ный объем информации.

При оценке размеров буфера необходимо принимать во внимание тот факт, что ре-

альный размер всегда должен быть немного больше расчетного, поскольку каждое со-

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

приблизительно в 28 байтов. Точный размер этой структуры не документируется и мо-

жет изменяться от версии к версии.

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

память для буфера, однако потоки, для работы которых требуется объем памяти, пре-

вышающий выделенный размер буфера, могут быть заблокированы. От увеличения раз-

 


 

 

мера буфера выигрывают те программы, которые часто отправляют сообщения или тре-

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

Параметр dwTimeout имеет значение только в том случае, если для установки со-

единения клиент вызывает функцию WaitNamedPipe(), которая изменяет период паузы,

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

в качестве параметра dwTimeout функции CreateNamedPipe(), однако с помощью функ-

ции WaitNamedPipe() клиент может задать другое значение.

Параметр lpsa представляет собой указатель на структуру SECURI-

TY_ATTRIBUTES, которая вам уже знакома. Значения переменных этой структуры оп-

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

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

дочерним процессом. Как обычно, если в этом поле будет оставлено значение NULL,

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

следоваться.

Следует отметить, что анонимныеканалы имеют характеристики, которые описы-

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

PIPE_TYPE_BYTE, PIPE_READMODE_BYTE, PIPE_WAIT, запрет асинхронного вво-

да/вывода и разрешение буферизации данных в сети.

При успешном выполнении функция CreateNamedPipe() возвращает соответст-

вующий дескриптор, при наличии ошибки – дескриптор 0xFFFFFFFF (т.е.

INVALID_HANDLE_VALUE). В приложениях, скомпилированных в среде Windows 98,


функция


CreateNamedPipe() всегда возвращает сообщение об ошибке


(INVALID_HANDLE_VALUE).

Сервер, открывший именованный канал, должен ожидать, пока этот канал не будет

открыт на другом конце программой-клиентом. Клиент может открыть свой конец кана-

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

функция CreateFile(). Эта же функция применяется и для открытия файлов на диске. Она

также работает с именованными каналами, устройствами связи и буферами вво-

да/вывода символьного консольного окна. С указанным набором объектов работают ко-

манды ReadFile() и WriteFile(). Применение унифицированного набора API-функций

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

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

бор флагов, рассмотрим функцию CreateFile() еще раз:


 

HANDLE CreateFile(LPCTSTR lpszName,


 

//имя канала (или файла)


DWORD fdwAccess,

 

DWORD fdwShareMode,


//доступ для чтения/записи (должен

// соответствовать атрибутам канала)

//для каналов обычно значение этой

//переменной равно 0 (совместное

//использование не допускается)


LPSECURITY_ATTRIBUTES lpsa, //привилегии доступа


DWORD fdwCreate,

 

DWORD fdwAttrsAndFlags,

HANDLE hTemplateFile);


//для каналов эта переменная должна иметь

//значение OPEN_EXISTING

//режимы сквозной записи и перекрытия

//игнорируется при наличии флага

//OPEN_EXISTING


 

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

функции CreateNamedPipe(). Если соединение между программой-сервером и програм-

мой-клиентом устанавливается по сети, в этой строке вместо точки (.) указывается сете-

вое имя серверного компьютера.

 

 



 

 

Параметр fdwAccess определяет, с какой целью (для чтения или для записи) будет

использоваться канал. Если канал был создан с флагом PIPE_ACCESS_OUTBOUND,

при вызове функции CreateFile() должно быть задано значение GENERIC_READ. Для

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

для работы с двухсторонним каналом - привилегии класса GENERIC_READ |

GENERIC_WRITE.

Параметр fdwShareMode(), как правило, имеет значение 0, предотвращая таким об-

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

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

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

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

меры для синхронизации операций записи и чтения.

Атрибуты безопасности, хранящиеся в параметре lpsa, вам уже знакомы. Флаг

fdwCreate должен иметь значение OPEN_EXISTING, поскольку функция CreateFile() не

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

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

lpszName соответствует объекту-каналу, использование этих флагов приведет к ошибке.

Последние два параметра функции CreateFile() обычно управляют атрибутами

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

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

При открытии существующего файла (флаг OPEN_EXISTING) объект сохраняет свои

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


именованного канала срабатывают два флага параметра


fdwAttrsAndFlags:


FILE_FLAG_WRITE_THROUGH и FILE_FLAG_OVERLAPPED. Клиент может устано-

вить флаги, которые отличаются от флагов, установленных сервером, разрешая или за-

прещая буферизацию в сети и асинхронный ввод/вывод в соответствии со своими по-

требностями.

На двух концах одного и того же канала могут быть установлены разные режимы

чтения или записи, однако при открытии дескриптора для клиента функция CreateFile()

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

свойдескрипторканала с помощью функции SetNamedPipeHandleState().

 

BOOL SetNamedPipeHandleState(


HANDLE hNamedPipe,

LPDWORD lpdwModes,

LPDWORD lpdwMaxCollect,


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

// флаги режима чтения и ожидания

// размер передающего буфера


LPDWORD lpdwCollectDataTimeout); // максимальное время, оставшееся

// до начала передачи

 

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

CreateNamedPipe() или CreateFile().


Параметр


lpdwModes, подобно


параметру


fdwPipeMode функции


CreateNamedPipe(), содержит комбинацию флагов, которые позволяют одновременно

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

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

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

PIPE_READMODE_BYTE или PIPE_READMODE_MESSAGE. (Если задать режим со-

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

возвратит код ошибки.) Режим чтения может использоваться в сочетании с флагом

PIPE_WAIT или PIPE_NOWAIT.

 



 

 

Двапоследнихпараметра используются только для каналов, устанавливающих

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

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

лы, созданные с атрибутом PIPE_FLAG_WRITE_THROUGH, который запрещает буфе-

ризацию в сети. Буферизация дает возможность системе комбинировать несколько

сообщений и передавать их одновременно, за один сеанс. Причем исходящие сообщения

накапливаются в буфере до тех пор, пока не произойдет заполнение буфера или не за-

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

метром lpdwMaxCollect, а значение временного интервала, выраженное в миллисекун-

дах, - параметром lpdwCollectDataTimeout.

Имеется три функции, позволяющие получитьинформациюоканале, не изменяя

его атрибутов [12].

Первая функция является "двойником" функции SetNamedPipeHandleState(), одна-

ко она кроме той информации, которая устанавливается функцией SetNamedPipeHan-

dleState(), позволяет получить много дополнительных сведений:

 

BOOL GetNamedPipeHandleState(


HANDLE hNamedPipe,

LPDWORD lpdwModes,

LPDWORD lpdwInstances,

LPDWORD lpcbMaxConnect,


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

// режимы чтения и ожидания

// количество экземпляров текущего канала

// максимальное количество байтов,


// накапливаемых до начала удаленной передачи

LPDWORD lpdwConnectTimeout, // максимальное время до начала удаленной

// передачи


LPTSTR lpszUserName,


// пользовательское имя процесса-клиента


DWORD dwMaxUserNameBuff); // размер буфера для хранения

// пользовательского имени, выраженный

// в количестве символов

 

Параметр lpdwModes может содержать флаги PIPE_READMODE_MESSAGE и

PIPE_NOWAIT. Если ни один из этих флагов не установлен, применяются байтовый ре-

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

Параметр lpdwInstances позволяет подсчитать текущее количество экземпляров

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

CreateNamedPipe() с одним и тем же именем канала.

Параметры lpcbMaxConnect и lpdwConnectTimeout возвращают ту же информа-

цию о сетевой буферизации, которая задается функцией SetNamedPipeHandleState().

Последниедвапараметра указанной функции дают серверу возможность полу-

чить информацию о клиенте. Они возвращают завершающиеся нулевым символом стро-

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

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

рацией системы и привилегиями безопасности. Имя пользователя может понадобиться

серверу для регистрации или отчетности, но скорее всего, этот параметр введен для со-

вместимости с OS/2, где он также используется. Параметр lpszUserName должен иметь

значение NULL, если дескриптор hNamedPipe принадлежит клиенту или, иными слова-

ми, если он был создан функцией CreateFile (а не функцией CreateNamedPipe).

Любому из параметров-указателей может быть присвоено значение NULL, что даст

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

Дополнительнаяинформацияоканале может быть возвращена и посредством

функции GetNamedPipeInfo(). Данная функция возвращает атрибуты, которые нельзя

 



 

 

изменить, чем и отличается от функции GetNamedPipeHandleState(), которая возвращает

атрибуты, изменяемые во время существования канала.

 

BOOL GetNamedPipeInfo(


HANDLE hNamedPipe,

LPDWORD lpdwType,

LPDWORD lpdwOutBuf,

LPDWORD lpdwInBuf,


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

// тип и флаги сервера

// размер выходного буфера канала, байты

// размер входного буфера канала, байты


LPDWORD lpdwMaxInstances);// максимальное количество экземпляров канала


 

Параметр


 

lpdwType может содержать либо один


 

из флагов


PIPE_TYPE_MESSAGE и PIPE_SERVER_END, либо оба флага одновременно. Если ни

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

который записывает информацию в байтовом режиме. Размеры входного и выходного

буферов задаются функцией CreateNamedPipe().

Параметр lpdwMaxInstances возвращает заданное функцией CreateNamedPipe()

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

существовать одновременно.

Обычно при выполнении операции чтения из канала прочитанное сообщение уда-

ляется из буфера. Однако с помощью функции PeekNamedPipe() сообщение можно про-

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

именованными каналами.

 

BOOL PeekNamedPipe(


HANDLE hPipe,

LPVOID lpvBuffer,

DWORD dwBufferSize,


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

//адрес буфера для получения данных

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


LPDWORD lpdwBytesRead,//возвращает количество прочитанных байтов

LPDWORD lpdwAvailable, //возвращает полное количество байтов

LPDWORD lpdwMessage); //возвращает количество непрочитанных байтов

//данного сообщения

 

Параметр lpvBuffer указывает место, куда функция PeekNamedPipe() может запи-

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

medPipe() не сможет прочитать больше байтов, чем задано параметром dwBufferSize,

даже если в канале еще осталась информация.

Параметр lpdwBytesRead возвращает данные о количестве байтов, которые функ-

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

оставшихся в этом сообщении. Параметр lpdwMessage игнорируется, если канал нахо-

дится в режиме чтения PIPE_READMODE_BYTE. В этом случае разбивка информации

на сообщения не производится. (Байтовый режим чтения применяется всеми анонимны-

ми каналами.)

Параметр lpdwAvailable возвращает информацию о суммарном количестве бай-

тов, содержащихся во всех сообщениях. Если в данный момент в буфере находится не-

сколько сообщений, значение *lpdwAvailable может превышать сумму значений пара-

метров *lpdwBytesRead и *lpdwMessage.

Допускается возвращение только части информации, с сохранением значения

NULL для остальных параметров. Например, если вам достаточно иметь информацию

лишь о том, сколько байтов данных находится в буфере, всем параметрам, кроме lpdwA-

vailabie, можно задать значение 0 или NULL.

 



 

 

Если канал находится в режиме чтения сообщений, функция PeekNamedPipe() все-

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

для нескольких сообщений. Кроме того, функция PeekNamedPipe() никогда не блокиру-

ет пустой канал, как это делает функция ReadFile() при установленном флаге

PIPE_WAIT. Режим ожидания не влияет на функцию PeekNamedPipe(), которая всегда

возвращает результат немедленно.

Все операции, которые выполнялись при создании канала - именованного или ано-

нимного, блокируемого или неблокируемого, байтового канала или канала сообщений, -

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

му каналу. Для операций непосредственно чтения - записи используются функции Wri-

teFile() и ReadFile(). Данные функции, как и CreateFile() рассмотрены нами ранее при

изучении файлового ввода-вывода. Однако рассмотрим их еще раз с учетом специфики

каналов.

 

BOOL WriteFile(


HANDLE hFile,

CONST VOID *lpBuffer,

 

DWORD dwBytesToWrite,

LPDWORD lpdwBytesWritten,


// куда записывать (канал или файл)

//указывает данные, которые должны быть

// записаны в файл

// количество записываемых байтов

// возвращает количество записанных байтов


LPOVERLAPPED lpOverlapped); // задает поддержку асинхронного

// ввода/вывода

BOOL ReadFile(


HANDLE hFile;

LPVOID lpBuffer;


// источник для чтения данных (канал или файл)

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

// прочитанных данных


DWORD dwBytesToRead;

 

LPDWORD lpdwBytesRead;


// количество байтов, которые должны быть

// прочитаны

// возвращает количество прочитанных байтов


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

 

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

тельно должно совпадать с размером буфера, однако превышать этот размер оно не мо-

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

щений, вы зададите параметру dwBytesToRead значение, меньшее, чем размер

следующего сообщения, функция ReadFile() прочитает только часть сообщения и воз-

вратит значение FALSE. Если после этого проанализировать причину ошибки, вызвав

функцию GetLastError(), она возвратит код ошибки ERROR_MORE_DATA. Чтобы про-

читать остаток сообщения, следует снова вызвать функцию ReadFile() или PeekNamed-

Pipe(). Если функция WriteFile() записывает данные в неблокируемый канал, который

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

вращает значение TRUE, однако значение lpdwBytesWritten окажется меньшим, чем зна-

чение dwBytesToWrite.

В зависимости от режима ожидания канала функции WriteFile() и ReadFile() могут

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

бодится на другом конце. Функция ReadFile() может быть заблокирована пустым кана-

лом вплоть до момента поступления нового сообщения.

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

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

поддержки асинхронного или перекрывающегося ввода/вывода, который рассмотрен

нами ранее.

 

 



 

 

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

нии команд ReadFileEx() и WriteFileEx(). Вместо того чтобы сигнализировать о своем

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

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

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

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

различным экземплярам одного канала. Операции синхронного ввода/вывода проще

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

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

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

того требует реальная ситуация.

При асинхронном вводе/выводе один и тот же поток может одновременно записы-

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

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

да/вывода выполняется системой в фоновом режиме. С помощью команды

WaitForMultipleObjects() поток можно блокировать вплоть до завершения всех отложен-

ных операций. Эффективность асинхронного ввода/вывода особенно ярко проявляется

при медленных сетевых соединениях. Кроме того, при наличии меньшего числа синхро-

низируемых потоков гораздо проще обеспечить защиту программных ресурсов.

Влюбоймоментклиент может вызвать функцию CreateFile() для открытия сво-

его конца именованного канала. Однако при этом могут возникнуть две проблемы [12].

• Серверу иногда необходимо знать, подключился ли клиент к каналу. От операции

записи в неподключенный канал пользы немного, и функция CreateFile() не сообща-

ет серверу о наличии соединения.

• Если все экземпляры канала заняты, функция CreateFile() постоянно возвращает

значение INVALID_HANDLE_VALUE, не устанавливая соединения. Клиент может

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

операция, инициированная другим клиентом.

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

ожидая условий, при которых выполнение подключения станет возможным. Для этого

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

Pipe().

 

BOOL ConnectNamedPipe(


HANDLE hNamedPipe,


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


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

 

BOOL WaitNamedPipe(


LPTSTR lpszPipeName,

 

DWORD dwTimeout);


// указывает на строку, которая задает

// имя канала

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


 

Эти координирующие функции работают только с именованными каналами, по-

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

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

уже выполнено.

Подобно функциям ReadFile() и WriteFile(), функция ConnectNamedPipe() обеспе-

чивает асинхронную реакцию. Параметр lpOverlapped содержит дескриптор события,

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

Функционирование команды ConnectNamedPipe() зависит от того, был ли канал

создан с указанием флага FILE_FLAG_OVERLAPPED и находится ли он в режиме

 

 



 

 

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

возможность ожидания.

Значения TRUE и FALSE, возвращаемые функцией ConnectNamedPipe(), являются

несколько неестественными. В частности, значение TRUE возвращается только в том

случае, если канал начинает свое существование в состоянии ожидания, а клиент под-

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

подключен к клиенту и команда работает асинхронно (завершается без ожидания) или

если она вызывается для канала, который не допускает ожидания, функция ConnectNa-

medPipe() всегда возвращает значение FALSE.

Функция ожиданияклиента WaitNamedPipe() реально не устанавливает никакого

соединения. Она возвращает значение TRUE, если канал доступен или становится дос-

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

вращает.

Клиент обычно циклически выполняет последовательность операций ожидания и

создания до тех пор, пока не будет получен действительный дескриптор канала. Функ-

ция WaitNamedPipe() считает канал доступным только в том случае, если сервер вызы-

вает функцию ConnectNamedPipe() в ожидании связи. Две эти функции работают вместе,

синхронизируя действия клиента и сервера. Однако если сервер создает новый канал,

который никогда не подключался ни к одному из клиентов, функция WaitNamedPipe()

возвращает значение TRUE, даже если это противоречит результату функции Connect-

NamedPipe(). Гарантировать соединение с помощью функции WaitNamedPipe() можно

только в том случае, если серверу известно о доступности канала. Если клиент разрыва-

ет соединение, сервер может ошибочно отреагировать на это событие. Кроме того, при

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

партнера. Распознавание только новых каналов и каналов, сформированных с помощью

функций ConnectNamedPipe() и WaitNamedPipe(), предотвращает отключение клиентов

во время процесса обмена информацией.

Следует отметить, что функция WaitForSingleObject() не работает с каналами, по-

скольку они не имеют сигнального состояния.

Для осуществлении связи подуплекснымканалам используется две функции:

TransactNamedPipe() и CallNamedPipe(). Эти функции комбинируют операции записи и

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

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

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

следующим условиям [12]:

• является именованным;

• использует флаг PIPE_ACCESS_DUPLEX;

• относится к типу канала сообщений;

• настроен на режим чтения сообщений.

Сервер устанавливает все эти атрибуты с помощью функции CreateNamedPipe().

При необходимости клиент может подкорректировать некоторые атрибуты с помощью

функции SetNamedPipeHandleState(). Режим блокировки не влияет на выполнение ко-

манд транзакций.

Отправление запроса

Функция TransactNamedPipe() отправляет запрос по каналу и ожидает ответа. Ис-



Поделиться:




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

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


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