Практика к лабораторной работе №2
Простейшая модель типа клиент-сервер
Хотя в приведенном примере в подготовке к лабораторной работе, неименованные каналы используются только для передачи данных между процессами, связанными ?родственными узами?, существует возможность использовать их и для передачи данных между совершенно разными процессами.
Для этого воспользуемся механизмом именованных каналов, который позволяет каждому процессу получить свой, собственный дескриптор канала. Передача данных в этих каналах подчиняется принципу FIFO (первым записан - первым прочитан). Именованные каналы отличаются от неименованных наличием имени, то есть идентификатора канала, фактически виден всем процессам системы. Для идентификации именованного канала создается файл специального типа pipe. Файлы именованных каналов являются элементами файловой системы, как и остальные файлы в ОС UNIX, и для них действуют те же права доступа. Файлы именованных каналов создаются функцией mkfifo(3). Первый параметр этой функции - строка, в которой передается имя файла, идентифицирующего канал, второй параметр - маска прав доступа к файлу. Функция mkfifo() создает канал и файл соответствующего типа. Если указанный файл канала уже существует, mkfifo() возвращает -1. После создания файла канала процессы, участвующие в обмене данными, должны открыть этот файл либо для записи, любо для чтения. После закрытия файла канала, файл (и канал) продолжают существовать. Для того, чтобы закрыть сам канал, нужно удалить его файл, например с помощью функции unlink(2).
Рассмотрим работу именованного канала на примере простейшей модели типа клиент- сервер. Программа-сервер создает канал и передает в него текст, вводимый пользователем с клавиатуры. Программа-клиент читает этот текст и выводит его на терминал.
Исходный текст серверной части:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#define fifo "./fifo" //объявление имени именованного канала
int main(int argc, char * argv[])
{
FILE * file_fifo; //структура для работы с файлом
char ch;
mkfifo(fifo, 0700); //создание канала, с именем fifo, с маской прав доступа 0700
file_fifo = fopen(fifo, "w"); //открытие канала на запись
if (file_fifo == NULL) //обработка ошибки открытия
{
errno=EBADFD; //File descriptor in bad state
perror(argv[0]);
return -1;
}
do
{
ch = getchar(); //считать символ
fputc(ch, file_fifo); //запись в канал
if (ch == 10) fflush(file_fifo);//принудительная очистка буферов канала, в результате чего клиент считывает все переданные символы.
} while (ch != 'q'); //ввод символов до символа 'q'
fclose(file_fifo); //закрытие файла
unlink(fifo); //удаление канала
return 0;
}
Исходный текст клиентской части:
#include <stdio.h>
#define fifo "./fifo"
int main ()
{
FILE * file_fifo; //структура для работы с файлом
char ch;
file_fifo = fopen(fifo, "r"); //открытие канала на чтение
do
{
ch = fgetc(file_fifo); //получение символа из канала
putchar(ch); //вывод этого символа на экран
} while (ch != 'q'); //до тех пор пока, символ не 'q'
fclose(file_fifo); //закрытие файла
unlink(fifo); //удаление канала
return 0;
}
Для краткости значение, возвращенное mkfifo(), на предмет ошибок не проверяется. В результате вызова mkfifo() с заданными параметрами в рабочей директории программы должен появиться специальный файл fifo. Далее в программе-сервере мы просто открываем созданный файл для записи:
mkfifo(fifo, 0700); //создание канала, с именем fifo, с маской прав доступа 0700
file_fifo = fopen(fifo, "w"); //открытие канала на запись
Считывание данных, вводимых пользователем, выполняется с помощью getchar(), а с помощью функции fputc() данные передаются в канал. Работа сервера завершается, когда пользователь вводит символ ?q?. Клиент открывает файл fifo для чтения как обычный файл.
Символы, передаваемые по каналу, считываются с помощью функции fgetc() и выводятся на экран терминала с помощью putchar(). Каждый раз, когда пользователь наживает ввод, функция fflush(), вызываемая сервером, выполняет принудительную очистку буферов канала, в результате чего клиент считывает все переданные символы. Получение символа ?q? завершает работу клиента.