Linux应用编程—7.有名管道
7.1 mkfifo函数详情
无名管道用于具有亲缘关系的进程之间通讯,比如:父子进程、兄弟进程。有名管道用于非亲缘关系进程之间的通讯。创建有名管道使用到的库函数是:mkfifo(),这里强调是库函数的原因是,mkfifo同时也是一个用户指令。使用man 查看时,如果不加选项,如:man mkfifo,则打开的是用户指令详情页。在man后面加上选项,如:man 3 mkfifo,则打开的是Linux编程手册,是创建有名管道的库函数。
NAME
mkfifo, mkfifoat - make a FIFO special file (a named pipe)
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mkfifo()函数,用来生成一个先入先出(first insert first out)的特殊文件,又叫有名管道。使用时要包含头文件sys/stat.h。
DESCRIPTION
mkfifo() makes a FIFO special file with name pathname. mode specifies the FIFO's permissions. It is modified by the process's umask in the usual way: the permissions
of the created file are (mode & ~umask).
A FIFO special file is similar to a pipe, except that it is created in a different way. Instead of being an anonymous communications channel, a FIFO special file is entered into the filesystem by calling mkfifo().
Once you have created a FIFO special file in this way, any process can open it for reading or writing, in the same way as an ordinary file. However, it has to be open
at both ends simultaneously before you can proceed to do any input or output operations on it. Opening a FIFO for reading normally blocks until some other process opens
the same FIFO for writing, and vice versa. See fifo(7) for nonblocking handling of FIFO special files.
int mkfifo(const char *pathname, mode_t mode); mkfifo()生成一个名字叫“pathname”的先入先出的特殊文件。mode指定这个文件的权限,一般情况下,它通过进程的掩码被修改:这个创建的文件的权限是(mode & ~umask)。
先入先出的特殊文件类似于管道,此外,它用不同的方式被创建。通过调用mkfifo()将一个先入先出的特殊文件输入到文件系统中,而不是作为一个匿名通讯通道。
一旦你用这种方式创建了有名管道,任何进程都可以打开它进程读写操作,像是一个普通的文件。然而,对其进行任何输入或输出操作之前,它必须在两端同时打开。打开一个fifo读取通常会阻塞,直到一些其它的进程打开同一个fifo进行写入。反之亦然。
RETURN VALUE
On success mkfifo() and mkfifoat() return 0. In the case of an error, -1 is returned (in which case, errno is set appropriately).
mkfifo()调用,成功返回0,失败返回-1.
7.2 有名管道简单应用
有名管道用于两个非亲缘关系的进程之间通讯,所以,我们需要两个.c文件。我们在进程1中循环读取有名管道的数据,当然一般情况下它是阻塞的。然后在进程2中通过main()函数参数入口往有名管道写入数据。
新建一个文件夹named_pipe,编写程序read_named_pipe.c,在该程序内,创建有名管道“FIFO_0”,然后利用open()打开,open()函数返回一个文件描述符fd,使用read()函数从这个文件描述符fd中读取数据。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main(void)
{
int ret = 0;
char buff[128];
int fd;
ret = mkfifo("FIFO_0", 666);
if(-1 == ret)
{
perror("mkfifo.");
}
printf("Waitting for the data from named_pipe:\n");
fd = open("FIFO_0", O_RDWR);
if(-1 == fd)
{
perror("open.");
}
while(1)
{
memset(buff, '\0', sizeof(buff));
read(fd, buff, sizeof(buff));
printf("read_named_pipe's is %s: \n", buff);
sleep(1);
}
return 0;
}
在终端中输入:gcc read_named_pipe.c -o read,指定编译为read文件,后续运行可执行文件输入:./read。
运行结果:
root@ubuntu:/home/sgk/Documents/Linux_Program/named_pipe# ./read
mkfifo.: File exists
Waitting for the data from named_pipe:
打印提示信息后,阻塞式读取有名管道中的数据。如果当前终端权限不够,代码不能执行到这里,需要切换su权限。
新建终端,打开named_pipe文件夹,输入:ls,查看文件,此时可以看到有名管道,名为:FIFO_0。然后新建一个.c文件,命名为write_named_pipe.c。在这个.c里,我们通过main()函数往有名管道写数据,所以我们需要main()函数待参数,如:int main(int argc, char *argv)。代码中,我们利用open()函数打开有名管道,此时,可以以“只写”的方式打开。open()函数返回一个文件描述符。我们将argv[1]的数据通过字符串拷贝函数strcpy()拷贝到缓存buff里,然后通过write()函数写入有名管道,完成通过有名管道发送数据。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
int ret = 0;
char buff[128];
int fd;
fd = open("FIFO_0", O_WRONLY);
if(-1 == fd)
{
perror("open.");
}
if(argc == 1)
{
printf("Please send somthing to pipe!\n");
exit(EXIT_FAILURE);
}
strcpy(buff, argv[1]);
write(fd, buff, sizeof(buff));
return 0;
}
编译:gcc write_named_pipe.c -o write,生成可执行文件write。然后在终端输入:./write 123456789,此时在第一个终端界面,我们收到:read_named_pipe’s is 123456789:
运行结果:
7.3 有名管道总结
有名管道用于非亲缘关系的进程之间通讯,通过创建一种特殊的先入先出文件。用到的库函数是mkfifo(),函数原型为:int mkfifo(const char * pathname, mode_t mode);pathname是有名管道的文件路径名,mode是该有名管道的权限。返回值0:成功;-1:失败。