Для обеспечения передачи информации между не родственными процессами используются поименованные каналы.
Именованные каналы отличаются от неименованных наличием имени, то есть идентификатора канала, потенциально видимого всем процессам системы. Для идентификации именованного канала создается файл специального типа pipe. Файлы именованных каналов создаются функцией mkfifo().
Именованный канал можно создать системным вызовом
mknod (namefile, IFIFO|0666, 0)
namefile - имя канала;
0666 - к каналу разрешен доступ на запись и на чтение любому запросившему процессу;
или int mkfifo(const char *fifoname, mode_t mode);
Первый параметр - путь, где будет располагаться FIFO (имя файла, идентифицирующего канал);
второй параметр определяет режим работы с FIFO (маска прав доступа к файлу).
Функции mkfifo() создает канал и файл соответствующего типа. Если указанный файл канала уже существует, mkfifo() возвращает -1. После создания файла канала процессы, участвующие в обмене данными, должны открыть этот файл либо для записи, любо для чтения.
Именованный канал может создать администратор системы командой
$/etc/mknod namefile p
$chmod 666 namefile
После закрытия файла канала, файл (и канал) продолжают существовать. Для того, чтобы закрыть сам канал, нужно удалить его файл, например с помощью последовательных вызовов unlink().
unlink(FIFO_NAME);
Пример: Рассмотрим работу именованного канала на примере простой системы клиент- сервер.
Клиент (считывает данные из FIFO):
#include <stdio.h>
#define FIFO_NAME "./fifofile" //в кавычках – имя файла-канала-FIFO
int main ()
{
FILE * f;
char ch;
f = fopen(FIFO_NAME, "r");
do
{
ch = fgetc(f);
putchar(ch);
} while (ch != 'q');
fclose(f);
unlink(FIFO_NAME);
return 0;
}
Сервер (вводит данные в FIFO):
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "./fifofile"
int main(int argc, char * argv[])
{
FILE * f;
char ch;
mkfifo(FIFO_NAME, 0600);
f = fopen(FIFO_NAME, "w");
if (f == NULL)
{
printf("Не удалось открыть файл\n");
return -1;
}
do
{
ch = getchar();
fputc(ch, f); //данные попадают в буфер
if (ch == 10) fflush(f); //при нажатии Enter (10), в файл записывается содержимое
//выходного буфера
} while (ch != 'q');
fclose(f);
unlink(FIFO_NAME);
return 0;
}
Программа-сервер создает канал и передает в него текст, вводимый пользователем с клавиатуры. Программа-клиент читает текст и выводит его на терминал. Программы из этого примера можно рассматривать как упрощенный вариант системы мгновенного обмена сообщениями между пользователями многопользовательской ОС. Вызов функции mkfifo() создает файл-идентификатор канала в рабочей директории программы:
mkfifo(FIFO_NAME, 0600);
где FIFO_NAME - макрос, задающий имя файла канала (в нашем случае - "./fifofile").
В качестве маски доступа мы используем восьмеричное значение 0600, разрешающее процессу с аналогичными реквизитами пользователя чтение и запись. Для краткости мы не проверяем значение, возвращенное mkfifo(), на предмет ошибок. В результате вызова mkfifo() с заданными параметрами в рабочей директории программы должен появиться специальный файл fifofile. Далее в программе-сервере мы просто открываем созданный файл для записи:
f = fopen(FIFO_NAME, "w");
Считывание данных, вводимых пользователем, выполняется с помощью getchar(), а с помощью функции fputc() данные передаются в канал. Работа сервера завершается, когда пользователь вводит символ “q”. Клиент открывает файл fifofile для чтения как обычный файл:
f = fopen(FIFO_NAME, "r");
Символы, передаваемые по каналу, считываются с помощью функции fgetc() и выводятся на экран терминала с помощью putchar(). Каждый раз, когда пользователь сервера наживает ввод, функция fflush(), вызываемая сервером , выполняет принудительную очистку буферов канала, в результате чего клиент считывает все переданные символы. Получение символа “q” завершает работу клиента.
Межпроцессное взаимодействие (SVID IPC IPC)
Ещё 3 механизма межпроцессного взаимодействия появились в Unix System V и были описаны в System V Interface Definition (SVID): это сообщения, разделяемая память и семафоры.
Интерфейсы трех механизмов SVID IPC (IPC – Inter Process Communication, межпроцессное взаимодействие) основаны на общих принципах. Для того чтобы разные процессы могли получить доступ к одному объекту системы, они должны «договориться» об идентификации этого объекта. Роль идентификатора для всех объектов System V IPC выполняет ключ – уникальное число, в пределах подсистемы System V IPC. Для того чтобы использовать один и тот же объект, программы должны использовать один и тот же ключ. Для каждого объекта IPC предусмотрены специальные функции чтения и записи, а также управляющая функция. Объекты System V IPC обладают живучестью ядра, а не файловой системы: при перезагрузке ядра все существующие объекты восстановлены не будут.