![]() |
Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | |
|
Windows API предоставляет еще один способ взаимодействия между процессами – именованные каналы, которые позволяют обмениваться в симплексном или дуплексном режиме байтовым потоком данных не только между процессами на одной машине, но и на разных машинах в локальной сети.
Именованный канал может работать в двух режимах:
Именованный канал создается на стороне сервера с помощью функции:
HANDLE WINAPI CreateNamedPipe(LPCTSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
Параметры
lpName | имя канала. Это имя будет использовано для доступа к проекции из другого процесса. Имя должно быть записано в следующем виде: \\.\pipe\имяканала «имяканала» может содержать любые символы, кроме обратного слеша. Общая длина имени не должна превышать 256 символов. Имена каналов не чувствительны к регистру. |
dwOpenMode | флаги именованного канала. Должен как минимум содержать режим доступа к каналу (один из трех): PIPE_ACCESS_DUPLEX – дуплексный канал; PIPE_ACCESS_INBOUND – симплексный канал от клиента к серверу PIPE_ACCESS_OUTBOUND – симплексный канал от сервера к клиенту и также может содержать необязательные флаги в том числе: FILE_FLAG_WRITE_THROUGH – режим сквозной записи. Если клиент и сервер находятся на разных машинах, то операция записи не вернет управление, пока данные не будут переданы по сети и не будут помещены во входные буферы канала на конечном узле. |
dwPipeMode | режим работы канала – состоит из нескольких групп флагов: 1) режим записи данных: PIPE_TYPE_BYTE – данные поступают в канал в виде потока байтов (не может быть использован одновременно с PIPE_READMODE_MESSAGE); PIPE_TYPE_MESSAGE – данные поступают в канал в виде потока сообщений. 2) режим чтения данных: PIPE_READMODE_BYTE – данные читаются в виде поток байтов; PIPE_READMODE_MESSAGE – данные читаются в виде пока сообщений. 3) PIPE_WAIT – операция чтения/записи блокирует поток до завершения операции и ряд других флагов. |
nMaxInstances | максимальное число экземпляров именованного канала с указанным именем. От 1 до PIPE_UNLIMITED_INSTANCES (255). Если указать PIPE_UNLIMITED_INSTANCES, то число экземпляров не ограничено (точнее ограничено системными ресурсами). |
nOutBufferSize | размер выходного буфера в байтах |
nInBufferSize | размер входного буфера в байтах |
nDefaultTimeOut | время тайм-аута по умолчанию в миллисекундах |
lpSecurityAttributes | указатель на структуру SECURITY_ATTRIBUTES – параметры безопасности именованного канала. Чтобы присвоить атрибуты защиты по умолчанию, передайте в этом параметре NULL. |
результат функции | Дескриптор объекта ядра или INVALID_HANDLE_VALUE – в этом случае подробности об ошибке можно получить с помощью GetLastError() |
Размер входных и выходных буферов является ориентировочным, фактическое значение система выберет сама. Буферы нужны для того, чтобы сохранять поступающие данные, если в данный момент сервер или клиент не могут их прочитать. В случае заполнения буфера система может расширить его размер, либо приостановить передачу данных с соответствующей стороны (соответственно поток на той «стороне» будет приостановлен).
После того как канал создан, сервер вызывает функции ожидания подключения клиента к каналу:
BOOL WINAPI ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped);
Параметры
hNamedPipe | дескриптор объекта «именованный канал» |
lpOverlapped | нами не используется (применяется для неблокирующих операций чтения/записи) |
результат функции | Если не равно 0 – клиент успешно подключен. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). Однако, если клиент выполнит попытку подключения в промежуток между CreateNamedPipe (либо DisconnectNamedPipe) и ConnectNamedPipe, тогда результат будет нулевым, а GetLastError() вернет ERROR_PIPE_CONNECTED – эта ситуация не является ошибочной и должна явным образом обрабатываться программистом. |
В случае успешного подключения экземпляр объекта «именованный канал», переданный через параметр hNamedPipe, будет связан исключительно для обмена данными только с тем клиентом, для которого и было произведено подключение. Для того чтобы другие клиенты могли подключаться, необходимо создать новый экземпляр именованного канала (функция CreateNamedPipe – здесь становится ясен смысл параметра nMaxInstances) и поставить его на ожидание подключения с помощью ConnectNamedPipe.
Подключенный экземпляр теперь может передавать/получать данные между сервером и клиентом с помощью функции чтения/записи из файла – это ReadFile и WriteFile (подробности далее). По завершении сеанса сервер либо закрывает экземпляр канал с помощью функции CloseHandle – при этом экземпляр уничтожается, либо отсоединяет клиента от экземпляра канала с помощью функции DisconnectNamedPipe:
BOOL WINAPI DisconnectNamedPipe(HANDLE hNamedPipe);
Параметры
hNamedPipe | дескриптор объекта «именованный канал» |
результат функции | Если не равно 0 – клиент успешно отключен. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). |
Следует помнить, что при закрытии или отсоединении экземпляра канала, данные записанные в канал сервером, но не прочтенные клиентом, уничтожаются. Чтобы гарантировать прочтение клиентом переданных данных используйте функцию FlushFileBuffers, которая не вернет управлении, пока данные не будут прочитаны.
Со стороны клиента для подключения к именованному каналу необходимо использовать функцию CreateFile:
HANDLE WINAPI CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
Параметры (для работы с именованными каналами):
lpFileName | имя канала. Имя должно быть записано в следующем виде: \\имясервера\pipe\имяканала «имясервера» - имя компьютера, где расположен сервер. Если это локальный компьютер, то можно указать точку – «.». |
dwDesiredAccess | доступ к объекту: GENERIC_READ – на чтение GENERIC_WRITE – на запись |
dwShareMode | режим разделения – укажите 0 |
lpSecurityAttributes | указатель на структуру SECURITY_ATTRIBUTES – параметры безопасности именованного канала. Чтобы присвоить атрибуты защиты по умолчанию, передайте в этом параметре NULL. |
dwCreationDisposition | указание что делать, если объект существует. В нашем случае – это OPEN_EXISTING – требовать существование именованного канала. |
dwFlagsAndAttributes | флаги и атрибуты. В нашем случае – это 0. |
hTemplateFile | файл-шаблон. В нашем случае – это NULL |
результат функции | Дескриптор объекта ядра или INVALID_HANDLE_VALUE – в этом случае подробности об ошибке можно получить с помощью GetLastError() |
Если на момент вызова именованный канал существует, но все его экземпляры заняты, CreateFile вернет INVALID_HANDLE_VALUE, а GetLastError() вернет ERROR_PIPE_BUSY. В этом случае клиент должен выполнить ожидание свободного экземпляра канала с помощью функции:
BOOL WINAPI WaitNamedPipe(LPCTSTR lpNamedPipeName, DWORD nTimeOut);
Параметры
lpNamedPipeName | имя канала |
nTimeOut | время тайм-аута ожидания в миллисекундах. Можно также укать следующие константы: NMPWAIT_USE_DEFAULT_WAIT – использовать тайм-аут по умолчанию, указанный при создании канала функцией CreateNamedPipe; NMPWAIT_WAIT_FOREVER – не возвращать управление, пока не станет доступен экземпляр канала |
результат функции | Если не равно 0 – экземпляр доступен. Если равно 0 – экземпляр не доступен, подробности об ошибке можно получить с помощью GetLastError(). |
Объект именованного канала, полученный от функции CreateFile имеет режим байтового чтения без сквозной записи. Чтобы изменить параметры объекта нужно использовать функцию SetNamedPipeHandleState:
BOOL WINAPI SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout);
Параметры
hNamedPipe | дескриптор объекта «именованный канал» |
lpMode | режим работы канала – состоит из нескольких групп флагов: 1) режим чтения данных: PIPE_READMODE_BYTE – данные читаются в виде поток байтов; PIPE_READMODE_MESSAGE – данные читаются в виде пока сообщений. 2) PIPE_WAIT – операция чтения/записи блокирует поток до завершения операции |
lpMaxCollectionCount | укажите NULL |
lpCollectDataTimeout | укажите NULL |
результат функции | Если не равно 0 – клиент успешно подключен. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). |
Ядро удаляет объект «именованный канал» после того как счетчик ссылок на объект станет равным нулю.
Чтение/запись в именованный канал
Чтение из именованного канала производится с помощью функции ReadFile:
BOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
Параметры
hFile | дескриптор объекта «именованный канал» |
lpBuffer | указатель на область памяти, куда поместить прочитанные данные |
nNumberOfBytesToRead | сколько байт нужно прочитать |
lpNumberOfBytesRead | указатель на переменную, в которую будет помещено число фактически прочитанных байт |
lpOverlapped | в нашем случае не используется = NULL |
результат функции | Если не равно 0 – функция успешно выполнилась. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). В случае если размер отправленного сервером сообщения не помещается в буфер пользователя, данные будут прочитаны до размера буфера, GetLastError() вернет ERROR_MORE_DATA, и пользователю необходимо прочесть остаток данных с помощью ReadFile. |
Запись в именованный канал производится с помощью функции WriteFile:
BOOL WINAPI WriteFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
hFile | дескриптор объекта «именованный канал» |
lpBuffer | указатель на область памяти, где находятся данные для записи |
nNumberOfBytesToWrite | сколько байт нужно записать |
lpNumberOfBytesWritten | указатель на переменную, в которую будет помещено число фактически записанных байт |
lpOverlapped | в нашем случае не используется = NULL |
результат функции | Если не равно 0 – функция успешно выполнилась. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). |
Windows API предоставляет функцию, которая ориентирована на работу с именованными каналами в режиме передачи сообщений, она выполняет запись сообщения и ждет ответа от сервера:
BOOL WINAPI TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped);
Параметры
hNamedPipe | дескриптор объекта «именованный канал» |
lpInBuffer | указатель на данные для отправки на сервер |
nInBufferSize | размер данных для отправки |
lpOutBuffer | указатель на область памяти, куда помещать ответ |
nOutBufferSize | размер области памяти для ответа |
lpBytesRead | размер полученных данных |
lpOverlapped | не используется |
результат функции | Если не равно 0 – функция успешно выполнилась. Если равно 0 – произошла ошибка, подробности об ошибке можно получить с помощью GetLastError(). В случае если размер отправленного сервером сообщения не помещается в буфер пользователя, данные будут прочитаны до размера буфера, GetLastError() вернет ERROR_MORE_DATA, и пользователю необходимо прочесть остаток данных с помощью ReadFile. |
Дата публикования: 2015-10-09; Прочитано: 343 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!