linux进程间通信之命名管道fifo用法及注意事项
普通管道pipe只能在相关进程之间使用,例如父子进程。两个完全独立不相关的进程可以使用fifo,也就是命名管道。
命名管道fifo头文件及原型:
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
函数返回值成功返回0,失败返回-1。
命名管道fifo可以使不相关的独立进程之间互相通信,通过路径名识别,文件系统中可见。命名管道建立后,进程间可像普通文件一样操作,可使用open(),write(),read()等函数。为了读取操作而打开的命名管道可在open时设置O_RDONLY;为写入操作而打开的命名管道可在open时设置O_WRONLY。
命名管道fifo遵循先入先出原则,读时从头部读取数据,写时从尾部写入数据。
命名管道fifo与普通文件操作之间的区别是不支持如lseek()等文件定位,命名管道fifo默认打开是阻塞的。如果需要非阻塞,需要在open时设置O_NONBLOCK.
对于读取进程,如果是阻塞方式打开,如果当前命名管道fifo中没有数据,则进程会一直阻塞,直到有数据写入。如果是非阻塞打开,无论有无数据,读取进程会立即返回,没有数据时返回0.
对于写入进程,如果是阻塞方式打开,进程会一直阻塞直到数据可以被写入。如果非阻塞打开,当没有读打开时,写入进程会打开失败,返回-1.
写入进程fifo_write_test.c代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define MYFIFO "myfifo"
- #define BUFF_SIZE 1024
- int main(int argc,char* argv[]) {
- char buff[BUFF_SIZE];
- int real_write;
- int fd;
- if(argc<=1){
- printf("Usage: ./fifo_write_test string\n");
- exit(1);
- }
- sscanf(argv[1],"%s",buff);
- // 测试FIFO是否存在,若不存在,mkfifo一个FIFO
- if(access(MYFIFO,F_OK)==-1){
- if((mkfifo(MYFIFO,0666)<0)&&(EEXIST!=errno)){
- printf("Can NOT create fifo file!\n");
- exit(1);
- }
- }
- //调用open以只写方式打开FIFO,返回文件描述符fd
- if((fd=open(MYFIFO,O_WRONLY))==-1){
- printf("Open fifo error!\n");
- exit(1);
- }
- //调用write将buff写到文件描述符fd指向的FIFO中
- if ((real_write=write(fd,buff,BUFF_SIZE))>0) {
- printf("Write into pipe: '%s'.\n",buff);
- exit(1);
- }
- close(fd);
- exit(0);
- }
读取进程fifo_read_test.c代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define MYFIFO "myfifo"
- #define BUFF_SIZE 1024
- int main() {
- char buff[BUFF_SIZE];
- int real_read;
- int fd;
- //access确定文件或文件夹的访问权限。即,检查某个文件的存取方式
- //如果指定的存取方式有效,则函数返回0,否则函数返回-1
- //若不存在FIFO,则创建一个
- if(access(MYFIFO,F_OK)==-1){
- if((mkfifo(MYFIFO,0666)<0)&&(EEXIST!=errno)){
- printf("Can NOT create fifo file!\n");
- exit(1);
- }
- }
- //以只读方式打开FIFO,返回文件描述符fd
- if((fd=open(MYFIFO,O_RDONLY))==-1){
- printf("Open fifo error!\n");
- exit(1);
- }
- // 调用read将fd指向的FIFO的内容,读到buff中,并打印
- while(1){
- memset(buff,0,BUFF_SIZE);
- if ((real_read=read(fd,buff,BUFF_SIZE))>0) {
- printf("Read from pipe: '%s'.\n",buff);
- }
- }
- close(fd);
- exit(0);
- }
两份代码分别编译执行后如下:
写入进程执行:./fifo_write_test abc
Write into pipe: 'abc'.
读取进程输出:Read from pipe: 'abc'.