本帖最后由 sdnumcu 于 2013-9-8 10:46 编辑
本文关键字: linux 管道通信,linux 进程通信方式,有名管道,FIFO 有名管道的创建可以使用函数mkfifo(),该函数类似于文件中的open()操作,可以指定管道的路径和打开的模式。用户还可以在命令行使用“mknod 管道名 p”来创建有名管道。 在创建管道成功后,就可以使用open()、read()和write()这些函数了。与普通文件的开发设置一样,对于为读而打开的管道可在open()中设置O_RDONLY,对于为写而打开的管道可在open()中设置O_WRONLY,在这里与普通文件不同的是阻塞问题。由于普通文件在读写时不会出现阻塞问题,而在管道的读写中却有阻塞的可能,这里的非阻塞标志可以在open()函数中设定为O_NONBLOCK。下面分别对阻塞打开和非阻塞打开的读写进行讨论。 对于读进程: ● 若该管道是阻塞打开,且当前FIFO内没有数据,则对读进程而言将一直阻塞到有数据写入。 ● 若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,则读函数将立刻返回0。 对于写进程: ● 若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。 ● 若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。 表1列出了mkfifo()函数的语法要点。 表1 mkfifo()函数语法要点 所需头文件 | #include <sys/types.h> #include <sys/state.h> | 函数原型 | int mkfifo(const char *filename,mode_t mode) | 函数传入值 | filename:要创建的管道 | mode | O_RDONLY:读管道 | O_WRONLY:写管道 | O_RDWR:读写管道 | O_NONBLOCK:非阻塞 | O_CREAT:如果该文件不存在,那么就创建一个新的文件,并用第3个参数为其设置权限 | O_EXCL:如果使用O_CREAT时文件存在,那么可返回错误消息。这个参数可测试文件是否存在 | 函数返回值 | 成功:0 | 出错:-1 |
表2再对FIFO相关的出错信息进行归纳,以方便用户查错。 表2 FIFO相关的出错信息 EACCESS | 参数filename所指定的目录路径无可执行的权限 | EEXIST | 参数filename所指定的文件已存在 | ENAMETOOLONG | 参数filename的路径名称太长 | ENOENT | 参数filename包含的目录不存在 | ENOSPC | 文件系统的剩余空间不足 | ENOTDIR | 参数filename路径中的目录存在但却非真正的目录 | EROFS | 参数filename指定的文件存在于只读文件系统内 |
下面的实例包含两个程序,一个用于读管道,另一个用于写管道。其中在读管道的程序中创建管道,并且作为main()函数里的参数由用户输入要写入的内容;读管道的程序会读出用户写入到管道的内容。这两个程序采用的是阻塞式读写管道模式。 写管道的程序如下: /* fifo_write.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MYFIFO "/tmp/myfifo" /* 有名管道文件名 */
#define MAX_BUFFER_SIZE PIPE_BUF /* 定义在limits.h中 */
int main(int argc, char * argv[]) /* 参数为即将写入的字符串 */
{
int fd;
char buff[MAX_BUFFER_SIZE];
int nwrite;
if(argc <= 1)
{
printf("Usage: ./fifo_write string\n");
exit(1);
}
sscanf(argv[1], "%s", buff);
/* 以只写阻塞方式打开FIFO管道 */
fd = open(MYFIFO, O_WRONLY);
if (fd == -1)
{
printf("Open fifo file error\n");
exit(1);
}
/* 向管道中写入字符串 */
if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0)
{
printf("Write '%s' to FIFO\n", buff);
}
close(fd);
exit(0);
} 读管道程序如下: /* fifo_read.c */
(头文件和宏定义同fifo_write.c)
int main()
{
char buff[MAX_BUFFER_SIZE];
int fd;
int nread;
/* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建 */
if (access(MYFIFO, F_OK) == -1)
{
if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))
{
printf("Cannot create fifo file\n");
exit(1);
}
}
/* 以只读阻塞方式打开有名管道 */
fd = open(MYFIFO, O_RDONLY);
if (fd == -1)
{
printf("Open fifo file error\n");
exit(1);
}
while (1)
{
memset(buff, 0, sizeof(buff));
if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0)
{
printf("Read '%s' from FIFO\n", buff);
}
}
close(fd);
exit(0);
} 为了能够较好地观察运行结果,需要把这两个程序分别在两个终端里运行,在这里首先启动读管道程序。读管道进程在建立管道后就开始循环地从管道里读出内容,如果没有数据可读,则一直阻塞到写管道进程向管道写入数据。在启动了写管道程序后,读进程能够从管道里读出用户的输入内容,程序运行结果如下。 终端一: $ ./fifo_read
Read 'FIFO' from FIFO
Read 'Test' from FIFO
Read 'Program' from FIFO
… 终端二: $ ./fifo_write FIFO
Write 'FIFO' to FIFO
$ ./fifo_write Test
Write 'Test' to FIFO
$ ./fifo_write Program
Write 'Program' to FIFO
…
|