1 Обзор
FIFO почти аналогичен конвейеру, поэтому FIFO также является потоком байтов. Порядок чтения из FIFO также такой же, как и порядок записи в FIFO. Емкость также ограничена, и это также может гарантировать, что работа запись не более PIPE_BUF байт атомарна Да суть FIFO тоже пайп, но направление передачи может быть двунаправленным.Самая большая разница между ними в том, что FIFO имеет имя в файловой системе, а метод открытия один и тот же как открытие обычного файла (используя open), чтобы можно было использовать FIFO для связи между несвязанными процессами (такими как клиент и сервер). (Если вы не знакомы с пайплайнами, вы можете прочитать другую мою статью о пайплайнахКанал межпроцессного взаимодействия Linux)
2. Создайте ФИФО
#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);//return 0 on success,or -1 on error
- Параметр режима указывает разрешения нового FIFO, то есть права доступа к файлам (rw-rw----)
- Параметр режима будет подвергнут операции XOR со значением umask в процессе, чтобы указать окончательное значение разрешения (поэтому обычно устанавливается umask(0)).
3. Откройте ФИФО
- FIFO успешно создан, и любой процесс может открыть его, если он проходит нормальную проверку прав доступа к файлам с исходно установленным режимом.
readFd=open(pathname,O_RDONLY);//打开只读方式
writeFd=open(pathname,O_WRONLY);//打开只写方式
- Открытие FIFO для чтения данных (флаг open() O_RDONLY) будет заблокировано до тех пор, пока другой процесс не откроет FIFO для записи данных (open() O_WRONLY). Соответственно, открытие FIFO для записи данных будет заблокировано до тех пор, пока другой процесс не откроет FIFO для чтения данных.
4. Единственный разумный способ использовать FIFO — настроить процесс чтения и процесс записи на обоих концах разума.
-
Это может гарантировать, что операция записи не более байтов PIPE_BUF каждый раз будет атомарной.При превышении байтов PIPE_BUF ядро будет разделять сообщение, что может запутать сообщения, отправленные другими пишущими.Если есть только один пишущий, то Это ограничение можно игнорировать, не беспокоясь о путанице.
-
Когда несколько клиентов считывают данные из FIFO, они будут конкурировать друг с другом, так что один клиент может прочитать ответное сообщение от других клиентов.
-
Использование FIFO в односерверных многоклиентских приложениях
Ядро серверной программы
// we get the permissions we want
umask(0);
if(mkfifo(SERVER_FIFO,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno!=EEXIST){
ERR_EXIT("mkfifo");
}
serveFd=open(SERVER_FIFO,O_RDONLY);
if(serveFd==-1){
ERR_EXIT("open");
}
for(;;){
//Read requests and send responses
if (read(serveFd, &req, sizeof(struct request)) != sizeof(struct request)) {
errMsg("ERROR reading request;discarding\n");
continue;
}
//Open client FIFO (previously created by client)
snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)req.pid);
clientFd=open(clientFifo,O_WRONLY);
if(clientFd==-1){
errMsg("open\n");
continue;
}
//send response and close FIFO
if(write(clientFd,&resp, sizeof(struct response))!= sizeof(struct response)){
errMsg("Error writing to FIFO");
}
if(close(clientFd)==-1){
errMsg("close");
}
}
Ядро клиентской программы
//create our FIFO (before sending request,to avoid a race)
umask(0);
snprintf(clientFifo,CLIENT_FIFO_NAME_LEN,CLIENT_FIFO_TEMPLATE,(long)getpid());
if(mkfifo(clientFifo,S_IRUSR|S_IWUSR|S_IWGRP)==-1&&errno!=EEXIST){
ERR_EXIT("mkfifo");
}
serverFd=open(SERVER_FIFO,O_WRONLY);
if(serverFd==-1){
ERR_EXIT("open");
}
if (write(serverFd, &req, sizeof(struct request)) != sizeof(struct request)) {
ERR_EXIT("write");
}
//open our FIFO,read and display response
clientFd=open(clientFifo,O_RDONLY);
if(clientFd==-1){
ERR_EXIT("open");
}
if(read(clientFd,&resp, sizeof(struct response))!= sizeof(response)){
ERR_EXIT("read");
}
if(close(clientFd)==-1){
ERR_EXIT("close");
}
5. Неблокирующий ввод-вывод
Когда процесс открывает один конец FIFO, процесс блокируется, если другой конец FIFO не был открыт. Но иногда блокировка нежелательна, вы можете указать O_NONBLOCK при вызове open().
fd=open("fifopath",O_RDONLY|O_NONBLOCK);
if(fd==-1){
errExit("open");
}
5.1 Существует две цели использования флага O_NONBLOCK при открытии FIFO.
- Это позволяет одному процессу открывать оба конца FIFO. Процесс сначала указывает флаг O_NONBLOCK при открытии FIFO для чтения данных, а затем открывает FIFO для записи данных.
- Это предотвращает взаимоблокировки между процессами, которые открывают два FIFO.
5.2 Неблокирующие операции чтения() и записи()
-
Флаг O_NONBLOCK влияет не только на семантику open(), но и на семантику последующих вызовов read() и write().
-
Флаг состояния O_NONBLOCK для открытых файлов может быть включен или отключен через fcntl().
включить флаг
int flags;
flags=fcntl(fd,F_GETFL);//Fetch open files status flags
flags|=O_NONBLOCK; // Enable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);// Update open files status flags
Отключить тег
flags=fcntl(fd,F_GETFL);
flags&=~O_NONBLOCK; //disable O_NONBLOCK bit
fcntl(fd,F_SETFL,flags);
6. Семантика чтения и записи в конвейерах и FIFO
Семантика чтения n байтов из канала или FIFO, содержащего p байтов
Семантика записи n байтов в канал или FIFO