FIFO有时又被称为命名管道,通过该管道的名字,可以实现在任意2个进程之间的消息传递:
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
int mkfifoat(int dirfd, const char *pathname, mode_t mode);
mkfifo的用法同open函数,该函数创建文件名pathname指定的管道文件,mode指定文件权限位,mkfifoat用法同openat,此时dirfd
代表文件路径,pathnmae代表文件名。注意mkfifo只是创建管道文件,如果要使用管道文件,则还要调用open来打开管道。
当open一个FIFO时,非阻塞标志(O_NONBLOCK)会产生下列影响。
在一般情况下(没有指定O_NONBLOCK),只读open要阻塞到某个其他进程为写而打开这个FIFO为止。类似地,只写open要阻塞到某个其他进程为读而打开它为止。
如果指定了O_NONBLOCK,则只读open立即返回,只写open将返回-1,并将errno设为ENXIO。
一个例子:
#include "unpipc.h"
#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"
void client(int, int), server(int, int);
int main(int argc, char **argv)
{
int readfd, writefd;
pid_t childpid;
/* 4create two FIFOs; OK if they already exist */
if ((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST))
err_sys("can't create %s", FIFO1);
if ((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST)) {
unlink(FIFO1);
err_sys("can't create %s", FIFO2);
}
if ( (childpid = Fork()) == 0) { /* child */
readfd = Open(FIFO1, O_RDONLY, 0);
writefd = Open(FIFO2, O_WRONLY, 0);
server(readfd, writefd);
exit(0);
}
/* 4parent */
writefd = Open(FIFO1, O_WRONLY, 0);
readfd = Open(FIFO2, O_RDONLY, 0);
client(readfd, writefd);
Waitpid(childpid, NULL, 0); /* wait for child to terminate */
Close(readfd);
Close(writefd);
Unlink(FIFO1);
Unlink(FIFO2);
exit(0);
}
void client(int readfd, int writefd)
{
size_t len;
ssize_t n;
char buff[MAXLINE];
/* 4read pathname */
Fgets(buff, MAXLINE, stdin);
len = strlen(buff); /* fgets() guarantees null byte at end */
if (buff[len-1] == '\n')
len--; /* delete newline from fgets() */
/* 4write pathname to IPC channel */
Write(writefd, buff, len);
/* 4read from IPC, write to standard output */
while ( (n = Read(readfd, buff, MAXLINE)) > 0)
Write(STDOUT_FILENO, buff, n);
}
void server(int readfd, int writefd)
{
int fd;
ssize_t n;
char buff[MAXLINE+1];
/* 4read pathname from IPC channel */
if ( (n = Read(readfd, buff, MAXLINE)) == 0)
err_quit("end-of-file while reading pathname");
buff[n] = '\0'; /* null terminate pathname */
if ( (fd = open(buff, O_RDONLY)) < 0) {
/* 4error: must tell client */
snprintf(buff + n, sizeof(buff) - n, ": can't open, %s\n",
strerror(errno));
n = strlen(buff);
Write(writefd, buff, n);
} else {
/* 4open succeeded: copy file to IPC channel */
while ( (n = Read(fd, buff, MAXLINE)) > 0)
Write(writefd, buff, n);
Close(fd);
}
}
代码功能,父进程从标准输入读一个文件名,并将该文件名写入管道FIFO1,子进程在管道 FIFO1中读取文件名,通过文件名,子进程读取文件内容,并将文件内容写入管道FIFO2为父进程提供服务,父进程读取管道FIFO2,取回数据。整个过程如下:
程序的管道结构如下: