С помощью труб могут общаться только родственные друг другу процессы, полученные с помощью fork(). Именованные каналы FIFO дают возможность обмена данными с абсолютно чужим процессом.
С точки зрения ядра ОС FIFO является одним из вариантов реализации трубы. Системный вызов mkfifo() предоставляет именованную трубу в виде объекта файловой системы. Как и для любого другого объекта, необходимо предоставлять процессам права доступа в FIFO, чтобы определить, кто может писать что-либо в FIFO, и кто может читать из нее. Несколько процессов могут записывать или читать FIFO одновременно. Режим работы с FIFO - полудуплексный, т.е. процессы могут общаться в одном направлении. Типичное применение FIFO - разработка приложений клиент-сервер.
Синтаксис функции для создания FIFO следующий:
#include <sys/stat.h>
int mkfifo(const char *fifoname, mode_t mode);
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd_fifo; /*дескриптор FIFO*/
char buffer[]="Текстовая строка для fifo\n";
char buf[100];
/*Если файл с таким именем существует, удалим его*/
unlink("/tmp/fifo0001.1");
/*Создаем FIFO*/
if((mkfifo("/tmp/fifo0001.1", O_RDWR)) == -1)
{
fprintf(stderr, "Невозможно создать fifo.........\n");
exit(0);
}
/*Открываем fifo для чтения и записи*/
if((fd_fifo=open("/tmp/fifo0001.1", O_RDWR)) == - 1)
{
fprintf(stderr, "Невозможно открыть fifo.....\n");
exit(0);
}
write(fd_fifo,buffer,strlen(buffer)) ;
if(read(fd_fifo, &buf, sizeof(buf)) == -1)
fprintf(stderr, "Невозможно прочесть из FIFO.......\n");
else
printf("Прочитано из FIFO : %s\n",buf);
return 0;
}
Если в системе отсутствует функция mkfifo(), можно воспользоваться общей функцией для создания файла
{ /*Невозможно создать fifo */
Флаг O_NONBLOCK может использоваться только при доступе для чтения. При попытке открыть FIFO с O_NONBLOCK для записи возникает ошибка открытия. Если FIFO закрыть для записи через close или fclose, это значит, что для чтения в FIFO помещается EOF.
Если несколько процессов пишут в один и тот же FIFO, необходимо обратить внимание на то, чтобы сразу не записывалось больше чем PIPE_BUF байтов. Это необходимо, чтобы данные не смешивались друг с другом. Установить пределы записи можно следующей программой (рис. 12):
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
unlink("fifo0001");
/*Создаем новый FIFO*/
if((mkfifo("fifo0001", O_RDWR)) == -1)
{
fprintf(stderr, "Невозможно создать FIFO\n");
exit(0);
}
printf("Можно записать в FIFO сразу %ld байтов\n",
pathconf("fifo0001", _PC_PIPE_BUF));
printf("Одновременно можно открыть %ld FIFO \n", sysconf(_SC_OPEN_MAX));
return 0;
}
При попытке записи в FIFO, который не открыт в данный момент для чтения ни одним процессом, генерируется сигнал SIGPIPE.
В следующем примере организуется обработчик сигнала SIGPIPE, создается FIFO, процесс-потомок записывает данные в этот FIFO, а родитель читает их оттуда. Пример иллюстрирует простое приложение типа клиент/сервер (рис. 13).
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
static volatile sig_atomic_t sflag;
static sigset_t signal_new, signal_old, signal_leer;
static void sigfunc(int sig_nr)
{
fprintf(stderr, "SIGPIPE вызывает завершение программы\n");
exit(0);
}
void signal_pipe(void)
{
if(signal(SIGPIPE, sigfunc) == SIG_ERR)
{
fprintf(stderr, "Невозможно получить сигнал SIGPIPE\n");
exit(0);
}
/*Удаляем все сигналы из множества сигналов*/
sigemptyset(&signal_leer);
sigemptyset(&signal_new);
sigaddset(&signal_new, SIGPIPE);
/*Устанавливаем signal_new и сохраняем его*/
/* теперь маской сигналов будет signal_old*/
if(sigprocmask(SIG_UNBLOCK, &signal_new, &signal_old) < 0)
exit(0);
}
int main()
{
int r_fifo, w_fifo; /*дескрипторы FIFO*/
char buffer[]="Текстовая строка для fifo\n";
char buf[100];
pid_t pid;
signal_pipe();
unlink("/tmp/fifo0001.1");
/*Создаем FIFO*/
if((mkfifo("/tmp/fifo0001.1", O_RDWR)) == -1)
{
fprintf(stderr, "Невозможно создать fifo.........\n");
exit(0);
}
pid=fork();
if(pid == -1)
{ perror("fork"); exit(0);}
else if(pid > 0) /*Родитель читает из FIFO*/
{
if (( r_fifo=open("/tmp/fifo0001.1", O_RDONLY)) < 0)
{ perror("r_fifo open"); exit(0); }
while(wait(NULL)!=pid); /*Ждем окончания потомка*/
read(r_fifo, &buf, sizeof(buf)); /*Читаем из FIFO*/
printf("%s\n",buf);
close(r_fifo);
}
else /*Потомок записывает в FIFO*/
{
if((w_fifo=open("/tmp/fifo0001.1", O_WRONLY)) < 0)
{ perror("w_fifo open"); exit(0); }
write(w_fifo, buffer, strlen(buffer)); /*Записываем в FIFO*/
close(w_fifo); /*EOF*/
exit(0);
}
return 0;
}