Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Использование каналов mailslot



Работа с данными каналами аналогична работе с файлами. Mailslot, определенным образом, аналогичен передаче данных как без канала, так и с каналом. По аналогии с бесканальным обменом информацией, можно использовать широковещательные адреса, а по аналогии с канальным – необходимо сначала подключиться, а затем передавать и принимать данные, в конце передачи данных нужно отключиться. К сожалению mailslot способен передавать информацию только в одну сторону, для двухсторонней передачи данных нужно создавать 2 mailslot-a в противоположных направлениях.

Для создания mailslot-a на сервере используется функция CreateMailslot. Она имеет 4 параметра. Первый параметр является наиболее важным, он задает имя mailslot-a. Формат этого параметра следующий: \\.\mailslot\имя, имя придумываем сами, от одной до тридцати одной буквы, цифры и знака подчеркивания (в языка С, С++ и их наследниках обратный слеш нужно удваивать). Второй параметр определяет максимальный размер сообщений, для широковещательных сообщений от 0 до 400 байт, для остальных от 0 до 4000, если указан 0, то подразумевается максимальное значение. С помощью третьего параметра можно задать время ожидания для операции чтения в миллисекундах, по истечении которого функция завершится с ошибкой, если указать в этом параметре значение MAILSLOT_WAIT_FOREVER, ожидание будет бесконечным. Последний четвертый параметр задает адрес структуры защиты, который позволяет подключаться к каналу использую авторизацию, к сожалению объем данного пособия мал, чтобы рассмотреть вопросы авторизации, данные вопросы описаны в системе документации MSDN, а мы будем работать без авторизации, для этого будем использовать в этом параметре значение NULL.

В случае успешного выполнения функцией CreateMailslot возвращается целое положительное число типа HANDLE – идентификатор mailslot-а, это значение нужно использовать в последующих функциях, при ошибке – значение INVALID_HANDLE_VALUE, код ошибки можно определить при помощи функции GetLastError. В качестве примера использования функции приведем следующий текст:

hMailslot = CreateMailslot(" \\\\.\\mailslot\\MyMailslot", 0, MAILSLOT_WAIT_FOREVER, NULL);

После создания mailslot-a сервером, клиент должен к нему подключиться. Для подключения применяется функция CreateFile. Эта функция, кроме подключения к mailslot-у может выполнять много других функций, из-за ее универсальности у нее 7 параметров, большинство из которых для mailslot-а может принимать строго определенные значения, поэтому мы рассмотрим только эти значения, остальные возможности данной функции рассмотрены в MSDN.

Первый параметр задает имя компьютера и имя mailslot-a, к которому подключаемся. Формат этого параметра следующий: \\ИмяКомпьютера\mailslot\ИмяMailslota. При использовании широковещательного сообщения вместо имени компьютера следует использовать имя домена или *. Если используется имя домена, то сообщения будут передаваться всем компьютерам домена, а если *, то все компьютерам сети.

Второй параметр для mailslot-a должен быть GENERIC_WRITE. Третий параметр – FILE_SHARE_READ. Четвертые параметр – NULL. Пятый параметр – OPEN_EXISTING. Шестой параметр – 0. Седьмой параметр – NULL.

Также, как и функция CreateMailslot, функция CreateFile в случае успешного выполнения возвращает целое положительное число типа HANDLE – идентификатор mailslot-а, при ошибке – значение INVALID_HANDLE_VALUE, код ошибки можно определить при помощи функции GetLastError. В качестве примера использования функции приведем следующий текст:

hMailslot = CreateFile(" \\\\MyServer\\mailslot\\MyMailslot", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

Для отправки сообщения по mailslot-у используется функция WriteFile. Эта функция имеет 5 параметров. Первый параметр – идентификатор mailslot-а, значение, которое вернула функция CreateMailslot или CreateFile. Второй параметр – указатель на область передаваемых данных. Третий параметр – размер передаваемых данных в байтах. Четвертый параметр – указатель на целочисленную переменную, в которую заносится количество реально отправленных байт. Пятый параметр нужен для асинхронной передачи данных, мы ей пользоваться не будем, поэтому используем значение NULL. Возвращает функция WriteFile логическое значение – истина, если данные отправлены без ошибки, ложь – если при отправке произошла ошибка, код ошибки можно получить с помощью функции GetLastError. В качестве примера использования функции WriteFile можно привести следующий фрагмент кода.

char a[100] = " Проба пера”;

unsigned int n;

bool l;

l = WriteFile(hMailslot, a, strlen(a)+1, & n, NULL);

if (l) {

// отправлено n байт

} else {

int e = GetLastError();

// произошла ошибка с кодом e

}

Для получения сообщения используется функция ReadFile, она имеем такие же параметры и возвращаемое значение как и функция WriteFile.

Для определения момента получения данных можно использовать функцию GetMailslotInfo, которая предназначена для определения состояния mailslot-а. Эта функция имеет 5 параметров. Первый параметр – идентификатор mailslot-а. Остальные 4 параметра – указатели на целочисленные беззнаковые переменные, которые после выполнения функции будут иметь следующие значения:

̶ максимальный размер сообщения;

̶ размер следующего сообщения;

̶ количества сообщений;

̶ времени ожидания.

Наиболее важным значением является количество сообщений, если оно больше нуля, то значит, что-то пришло и можно вызывать функцию ReadFile. Если некоторый из вышеперечисленных значений нас не интересуют, то можно поставить NULL. В качестве примера использования функций GetMailslotInfo и ReadFile можно привести следующий фрагмент кода.

char a[4001];

unsigned int n = 0;

bool l;

GetMailslotInfo(hMailslot, NULL, NULL, & n, NULL);

if (n > 0) {

l = ReadFile(hMailslot, a, 4000, & n, NULL);

if (l) {

    // получено n байт

} else {

    int e = GetLastError();

    // произошла ошибка с кодом e

} /

} else {

// ничего не получено

}  

Данный код можно вызывать в цикле или по таймеру.

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

На рис. 3.1 показан дизайн программ, использующих mailslot. Программы две: клиент и сервер, но дизайн у них одинаковый, отличие только в заголовке окна, поэтому рисунок один.

Рис. 3.1. Дизайн программ клиент и сервер, использующих mailslot

Рассмотрим основные действия программ. При старте программ (событие Load формы) выполняются создание mailslot-а с именем client для клиента и server для сервера (функция CreateMailslot).

При нажатии кнопки «Отправить»:

̶ преобразование содержимого полей ввода из типа String в массив типа char,

̶ формирование строки подключения вида \\ИмяКоппьютера\mailslot\ИмяMailslot-a,

̶ подключение к mailslot-у (CreateFile),

̶ отправка сообщения (WriteFile).

̶ отключение от mailslot-а (CloseHandle).

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

̶ проверка наличия полученных сообщений (GetMailslotInfo);

̶ если полученные сообщения есть, то получение данных (ReadFile).

После вызова функции проверяется код возврата, если он окажется ошибочным, то выдается соответствующее сообщение. Текст программы «Клиент», использующей mailslot, приведен в приложении 5, программа «Сервер» практически полностью совпадает с программой «Клиент» с той лишь разницей, что следует заманить слово client

на слово сервер и обратно.

Использование каналов pipe

В предыдущем пункте мы рассмотрели канал передачи данных mailslot. К достоинствам данного канала можно отнести:

̶ возможность широковещательной посылки данных;

̶ относительную простоту разработки приложений.

Однако у mailslot-а имеются существенные недостатки:

̶ маленький объем передаваемых данных (всего 4 Кбайт);

̶ односторонность передачи данных;

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

В принципе эти недостатки можно обойти, однако это существенно усложняет приложение и поэтому возможно следует использовать другой вид канала – pipe.

Существуют две разновидности каналов Pipe – именованные (Named Pipes) и анонимные (Anonymous Pipes). Однако анонимные каналы используются только в пределах одного компьютера и нам не подходят. Мы будем использовать исключительно именованные каналы.

Как и в случае канала mailslot, работа с каналом pipe аналогична работе с файлами, некоторые функции те же самые, однако возможны другие параметры, поэтому рассмотрим их подробно. В отличии от mailslot-а, pipe является двухсторонним каналом, однако «Клиент» и «Сервер» достаточно сильно отличаются друг от друга. «Сервер» создает pipe, а «Клиент» подключается к нему.

Для создания pipe-a на сервере используется функция CreateNamedPipe. Она имеет 8 параметров.

Первый параметр является наиболее важным, он задает имя pipe-a. Формат этого параметра следующий: \\.\ pipe\имя, как и в случае с mailslot-ом, имя придумываем сами, от одной до тридцати одной буквы, цифры и знака подчеркивания (в языка С, С++ и их наследниках обратный слеш нужно удваивать).

Второй параметр – режим открытия канала, вариантов режимов открытия достаточно много, подробно о них можно прочитать в MSDN, рекомендуемое значение PIPE_ACCESS_DUPLEX, оно означает, что канал будет двухсторонний.

Третий параметр – режим работы канала, также много вариантов, рекомендуемый вариант PIPE_TYPE_BYTE|PIPE_NOWAIT, он означает, что прием и передача данных будет происходить байтами без ожидания. Вариант «без ожидания» означает, что любая операция приема или передачи данных лишь начинает операцию, выполнение операции будет происходить параллельно с продолжение работы программы. При таком режиме работы не происходит «зависание» программы, как в случае с ожиданием, когда при выполнении операции получения или передачи данных происходит останов выполнения программы до момента окончания операции.

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

Пятый и шестой параметры означают размер выходного и входного буферов в байтах, рекомендуемое значение – 1024.

Седьмой параметр – время ожидания окончания в миллисекундах. Данный параметр имеет смысл только в режиме с ожидание, рекомендуемое значение – 5000.

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

В случае успешного выполнения функцией CreateNamedPipe возвращается целое положительное число типа HANDLE – идентификатор pip-а, это значение нужно использовать в последующих функциях, при ошибке – значение INVALID_HANDLE_VALUE, код ошибки можно определить при помощи функции GetLastError. В качестве примера использования функции приведем следующий текст:

hPipe = CreateNamedPipe(L" \\\\.\\pipe\\MyServ", PIPE_ACCESS_DUPLEX,

PIPE_TYPE_BYTE|PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES,

1000, 1000, 5000,    NULL);

После создания pipe-a сервером, клиент должен к нему подключиться. Для подключения применяется функция CreateFile. Мы уже встречались с этой функцией, когда рассматривали mailslot, эта функция имеет 7 параметров, большинство из которых для pipe-а может принимать строго определенные значения, поэтому мы рассмотрим только эти значения, остальные возможности данной функции рассмотрены в MSDN.

Первый параметр задает имя компьютера и имя pipe-a, к которому подключаемся. Формат этого параметра следующий: \\ИмяКомпьютера\ pipe \ИмяMailslota. Второй параметр для pipe-a должен быть GENERIC_READ|GENERIC_WRITE. Третий параметр – FILE_SHARE_READ. Четвертые параметр – NULL. Пятый параметр – OPEN_EXISTING. Шестой параметр – FILE_FLAG_OVERLAPPED. Седьмой параметр – NULL.

Также, как функции CreateMailslot и CreateNamedPipe, функция CreateFile в случае успешного выполнения возвращает целое положительное число типа HANDLE – идентификатор pipe-а, при ошибке – значение INVALID_HANDLE_VALUE, код ошибки можно определить при помощи функции GetLastError. В качестве примера использования функции приведем следующий текст:

hPipe = CreateFile(L" \\\\MyComp\\pipe\\MyServ", GENERIC_READ|

GENERIC_WRITE, FILE_SHARE_READ, NULL,

OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

В ответ на вызов клиентом CreateFile, сервер должен вызвать функцию ConnectNamedPipe, данная функция создает реализацию канала. Она имеет два параметра. Первый параметр – идентификатор pipe-а. Второй параметр мы использовать не будем и подставим NULL. Возвращает функция логическое значение, однако оно не очень интересно, больший интерес вызывает значение, Которое вернет функция GetLastError. Эта функция может вернуть значение:

̶ ERROR_PIPE_LISTENING – если с момента предыдущего вызова функции ConnectNamedPipe к серверу не подключился ни один клиент;

̶ ERROR_PIPE_CONNECTED – если клиент подключился;

̶ ERROR_NO_DATA – если клиент отключился;

̶ иное значение – ошибка.

Если произошло отключение клиента, то следует вызвать функцию DisconnectNamedPipe с единственным параметром – идентификатором pipe-a, для освобождения ресурсов реализации канала с данным клиентом.

В качестве примера использования функций ConnectNamedPipe и DisconnectNamedPipe можно привести следующий код программы:

unsigned int fConnect = 0;

ConnectNamedPipe(hPipe, NULL);

unsigned int LastError = GetLastError();

if (LastError == ERROR_PIPE_LISTENING) {

        // Нет подключения

        fConnect = 0

} // if

if (LastError == ERROR_PIPE_CONNECTED) {

        if (fConnect == 0) {

                  // Клиент подключен

        } // if

        fConnect = 1;

} // if

if (LastError == ERROR_NO_DATA) {

        // Клиент отключен

        DisconnectNamedPipe(hPipe);

        fConnect = 0;

} // if

Для отправки сообщения по pipe-у так же, как и по mailslot-у, используется функция WriteFile. Эта функция имеет 5 параметров. Первый параметр – идентификатор mailslot-а, значение, которое вернула функция CreateMailslot или CreateFile. Второй параметр – указатель на область передаваемых данных. Третий параметр – размер передаваемых данных в байтах. Четвертый параметр – указатель на целочисленную переменную, в которую заносится количество реально отправленных байт. Пятый параметр нужен для асинхронной передачи данных, мы ей пользоваться не будем, поэтому используем значение NULL. Возвращает функция WriteFile логическое значение – истина, если данные отправлены без ошибки, ложь – если при отправке произошла ошибка, код ошибки можно получить с помощью функции GetLastError. В качестве примера использования функции WriteFile можно привести следующий фрагмент кода.

char a[100] = " Проба пера”;

unsigned int n;

bool l;

l = WriteFile(hPipe, a, strlen(a)+1, & n, NULL);

if (l) {

// отправлено n байт

} else {

int e = GetLastError();

// произошла ошибка с кодом e

}

Для получения сообщения используется функция ReadFile, она имеем такие же параметры и возвращаемое значение, как и функция WriteFile, за исключением последнего параметра, который является указателем на структуру OVERLAPPED. Данная структура нужна для получения данных «без ожидания», в нее записывается информация о процессе получения данных, т.к. функция ReadFile только начинает процесс получения данных. Для наблюдения за процессом необходимо в цикле или по таймеру вызывать функцию GetOverlappedResult, которая имеет 4 параметра. Первый параметр – идентификатор pipe-a. Второй параметр – указатель на структуру OVERLAPPED, такой же, как в функции ReadFile. Третий параметр – указатель на целую беззнаковую переменную, в которую будет занесено количество полученных байт. Четвертый параметр мы использовать не будем и укажем там NULL.

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

Пример программ приема и передачи данных по каналу pipe, аналогично примерам с протоколами UDP и TCP, данный пример состоит из двух программ «Клиент» и «Сервер». Дизайн программы «Клиент» приведен на рис. 3.2, дизайн программы «Сервер» приведен на рис. 3.3.

Рис. 3.2. Дизайн программы «Клиент», использующей канал pipe

Рис. 3.3. Дизайн программы «Сервер», использующей канал pipe

Рассмотрим основные действия программ. При старте программ «Сервер» (событие Load) создается канал pipe (функция CreateNamedPipe).

 При завершении программ «Сервер» (событие FormClosed) канал закрывается (функция CloseHandle).

При нажатии кнопки «Подключиться» программы «Клиент» выполняются следующие действия:

̶ преобразование содержимого поля ввода «Имя коипьютера» из типа String в массив типа char;

̶ формирование строки подключения в виде " \\\\ИмяСервера\\pipe\\ИмяPipe";

̶ подключение к серверу (функция CreateFile);

̶ инициализация чтения данных (ReadFile), данных в этот момент времени еще нет, но операция «без ожидания», поэтому здесь мы ее начнем, а программа продолжит выполнение дальше, как данные поступят, так программа их и считает;

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

При нажатии кнопки «Отправить» обеих программ:

̶ преобразование содержимого поля ввода «Текст сообщения» из типа String в массив типа char;

̶ отправка сообщения (WriteFile).

При нажатии кнопки «Отключиться» программы «Клиент» – отключение от сервера (CloseHahdle).

Для определения момента подключения или отключения и для приема сообщений в программах создан таймер и определена функция обработки таймера. В программе «Сервер» данная функция выполняет следующие действия:

̶ вызывает функцию подключения клиента (ConnectNamedPipe);

̶ если код ошибки функции подключения клиента равен ERROR_PIPE_LISTENING, то подключения нет;

̶ если код равен ERROR_PIPE_CONNECTED, то произошло подключение;

̶ если код равен ERROR_NO_DATA, то произошло отключение, следует вызвать функцию DisconnectNamedPipe для освобождения ресурсов подключения;

̶ если есть подключение, то инициализация чтения данных (ReadFile).

В программе «Клиент» по таймеру только проверяется ход выполнения чтения (функция GetOverlappedResult).

После вызова функции проверяется код возврата, если он окажется ошибочным, то выдается соответствующее сообщение. Текст программы «Клиент» приведен в приложении 6, «Сервер» в приложении 7.

3.3. Контрольные вопросы

1. Для чего используется функция CreateMailslot.

2. Для чего используется функция CreateNamedPipe.

3. Для чего используется функция CreateFile.

4. Для чего используется функция ReadFile.

5. Для чего используется функция WriteFile.

6. Для чего используется функция CloseHandle.

7. Для чего используется функция GetMailslotInfo.

8. Для чего используется функция ConnectedNamePipe

9. Для чего используется функция DisconnectedNamedPipe.

10. С помощью какой функции создается Maislot со стороны сервера

11. С помощью какой функции создается Pipe со стороны сервера

12. С помощью какой функции осуществляется подключение к Maislot-у со стороны клиенты

13. С помощью какой функции осуществляется подключение к Pipe-у со стороны клиенты

14. С помощью какой функции осуществляется передача данных по Mailslot-у

15. С помощью какой функции осуществляется передача данных по Pipe-у

16. С помощью какой функции осуществляется прием данных по Pipe-у

17. С помощью какой функции осуществляется прием данных по  Mailslot-у

18. С помощью какой функции осуществляется отключение по Mailslot-у

19. С помощью какой функции осуществляется отключение по Pipe-у

20. С помощью какой функции можно определить пришло ли сообщение по Mailslot-у

21. С помощью какой функции можно определить пришло ли сообщение по Pipe-у

22. Что входит в адрес в Mailslot-e

23. Что входит в адрес в Pipe-e

24. Что обозначает собственный компьютер в Mailslot-e

25. Что обозначает собственный компьютер в Pipe-e

26. Что обозначает широковещательный адрес в Mailslot-e

27. Что обозначает широковещательный адрес в Pipe-e

 


Поделиться:



Последнее изменение этой страницы: 2020-02-16; Просмотров: 207; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.089 с.)
Главная | Случайная страница | Обратная связь