Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб.практикумСП.doc
Скачиваний:
39
Добавлен:
31.03.2015
Размер:
5.99 Mб
Скачать

13.8. Именованные каналы

Роль именованных каналов в разработке программных средств коммуникации процессов ОС Unix чрезвычайна велика. Это объясняется тем, что круг задач, решаемых с использованием неименованных каналов, в основном ограничивается созданием коммуникаций между процессами родственниками, чего, очевидно, зачастую оказывается недостаточно. Отличительной особенностью именованных каналов ОС Unix является то, что каждому именованному каналу соответствует один элемент некоторого каталога ОС Unix, что делает возможным осуществление ссылки к нему по имени файла, хранящемуся в поле имени соответствующего ему элемента каталога. Использование именованных каналов позволяет реализовать коммуникации между процессами, не связанными родственными отношениями.

Именованные каналы меньше ограничены, чем неименованные каналы, и обладают следующими преимуществами:

  • имеют имя, которое существует в файловой системе;

  • могут использоваться несвязанными процессами;

  • существуют, пока не удалены явно.

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

  • путем запуска утилиты mknod;

  • путем использования системного вызова mknod().

Чтобы создать именованный канал с помощью утилиты mknod, следует указать опцию p. Режим именованного канала может быть установлен через утилиту chmod для того, чтобы позволить другим получить доступ к создаваемому каналу. Ниже представлен пример этой процедуры:

$ mknod myPipe p создать конвейер

$ chmod ug+rw myPipe обновить права

$ ls -lg myPipe посмотреть атрибуты

prw-rw---- 1 glass cs 0 Feb 27 12:38 myPipe

$ приглашение к вводу следующей команды

Обратите внимание, что тип именованного канала – это символ p в первой позиции листинга утилиты ls.

Чтобы создать именованный канал через системный вызов mknod(), следует определить S_IFIFO в качестве режима файла. Режим канала затем может быть изменен путем использования системного вызова chmod(). Вот отрывок Си кода, который создает именованный канал с разрешением чтения и записи для владельца и группы:

mknod (“myPipe”, S_IFIFO, 0); /* Создать именованный канал */

chmod (“myPipe”, 0660); /* Изменить его флаги разрешения */

Независимо от того, как создается именованный канал, результат один и тот же: специальный файл добавляется в файловую систему. Как только именованный канал открыт через системный вызов open(), другой системный вызов - write() - добавляет данные в начало очереди FIFO, и read() удаляет данные с конца FIFO – очереди. Когда процесс закончил использовать именованный канал, он должен закрыть его с помощью системного вызова close(), а когда именованный канал перестает быть нужным, его необходимо удалить из файловой системы через системный вызов unlink().

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

  • если процесс пробует открыть именованный канал только для чтения, и нет процесса, который в настоящее время открыл файл для записи, читатель будет ждать, пока процесс не откроет файл для записи. Но если установлен флаг O_NONBLOCK/O_NDELAY, тогда системный вызов open() сразу завершиться нормально;

  • если процесс пробует открыть именованный канал только для записи, и нет процесса, который в настоящее время открыл этот файл для чтения, писатель будет ждать, пока процесс не откроет файл для чтения. Но если установлен флаг O_NONBLOCK/O_NDELAY, тогда системный вызов open() сразу завершиться с ошибкой;

  • именованные каналы не работают через сеть.

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

  • единственный читающий процесс выполняется, создавая именованный канал aPipe. Затем процесс читает и выводит заканчивающиеся символом NULL строки из канала, пока канал не закрывается всеми пишущими процессами;

  • один или несколько пишущих процессов выполняются, каждый из них открывает именованный канал aPipe и посылает ему три сообщения. Если канал не существует, когда писатель пытается открыть его, писатель повторяет попытку каждую секунду, пока не завершится нормально. Когда все сообщения писателя посланы, он закрывает канал и выходит.

Код программы читатель.

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

main()

{

int fd;

char str[100];

unlink(“aPipe”); /* Удалить именованный канал, если он существует */

mknod (“aPipe”, S_IFIFO, 0); /* Создать именованный канал */

chmod (“aPipe”, 0660); /* Изменить его права */

fd = open (“aPipe”, O_RDONLY); /* Открыть его для чтения */

while (readLine (fd, str)) /* Вывести получаемые сообщения */

printf (“%s\n”, str);

close (fd); /* Закрыть канал */

}

readLine (fd, str)

int fd;

char* str;

/* Читает отдельную, заканчивающуюся NULL, строку в str из fd */

/* Возвращает 0, когда достигнут конец ввода, и 1 - иначе */

{

int n;

do /* Читать символы до NULL или конца ввода */

{

n = read (fd, str, 1); /* Читать один символ */

}

while (n > 0 && *str++ != NULL);

return (n > 0); /* Возвращает ложь, если конец ввода */

}

Код программы писатель.

#include <stdio.h>

#include <fcntl.h>

main()

{

int fd, messageLen, i;

char message [100];

/* Подготовить сообщение */

sprintf (message, “Hello from PID %d”, getpid());

messageLen = strlen (message) + 1;

do /* Пытаться открыть файл до успеха */

{

fd = open (“aPipe”, O_WRONLY); /* Открыть именованный канал для записи*/

if (fd = = -1) sleep (1); /* Пытаться снова через 1 секунду */

}

while (fd = = -1);

for (i = 1; i <= 3, i++) /* Послать три сообщения */

{

write (fd, message, messageLen); /* Записать сообщение в канал */

sleep (3); /* Подождать немного */

}

close (fd); /* Закрыть дескриптор канала */

}