本文关键字: 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
…
本文选自华清远见嵌入式培训教材《从实践中学嵌入式Linux应用程序开发》
热点链接:
1、标准流管道
2、无名管道系统调用
3、Linux下进程间通信方式-管道
4、Linux下进程间通信
5、实验:编写守护进程
更多新闻>> |