[置顶] 【Linux】 进程通信--命名管道
2016-07-05 16:55
423 查看
在之前的博客中介绍了进程通信中的无名管道通信pipe,也对无名管道的局限性进行了剖析。
在这里,提出命名管道的概念FIFO,可解决无名管道的局限性,命名管道到底是通过什么机制进行通信的?请看下面
命名管道(FIFO)
————顾名思义,first input first output,按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
1.概念
管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管 道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO 相互通信。
2.命名管道的创建与读写
Linux下有两种⽅方式创建命名管道。一是在Shell下交互地建立一个命名管道;
二是在程序中使⽤用系统函数建⽴立命名管道。Shell⽅方式下可使⽤用mknod或mkfifo命令。
下⾯面命令使⽤用 mknod创建了⼀一个命名管道:
创建命名管道的系统函数有两个:mknod和mkfifo。
两个函数均定义在头⽂文件sys/stat.h, 函数原型如下:
函数mknod参数中path为创建的命名管道的全路径名:mod为创建的命名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。
mknod和mkfifo两个函数调用成功都返回0,失败都返回 -1。
下面使用mknod函数创建了⼀个命名管道:
函数mkfifo前两个参数的含义和mknod相同下面是使用mkfifo的示例代码:
S_IFIFO|0666 指明创建一个命名管道且存取权限为0666,即创建者,与创建者同组的用户,其他用户对该命名管道的访问权限都是可读可写(注意umask对生成的管道文件权限的影响)
命名管道创建后就可以使⽤用了,命名管道和管道的使用方法基本是相同的。只是使用命 名管道时,必须先调⽤用open()将其打开。因为命名管道是一个存在于硬盘上的文件,而管道 是存在于内存中的特殊文件。
注意,调用open()打开命名管道的进程可能会被阻塞。但如果同时用读写方式 (O_RDWR)打开,则一定不会导致阻塞;如果以只读方式(O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写方打开管道;同样以写方式(O_WRONLY)打开也会阻塞直到有读方式打开管道。
三.总结
文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识⼀一 个IPC通道。 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似。 由于Linux中所有的事物都可被视为⽂文件,所以对命名管道的使用也就变得与文件操作非常的统⼀,也使它的使用非常方便,同时我们也可以像平常的文件名⼀样在命令中使用。
创建命名管道可以用两个函数,函数原型如下:
这两个函数都能创建⼀一个FIFO文件,注意是创建⼀一个真实存在于文件系统中的文件, filename指定了文件名,而mode则指定了文件的读写权限。mknod是比较老的函数,而使用 mkfifo函数更加简单和规范,所以建议在可能的情况下,尽量使用mkfifo而不是mknod。 mkfifo函数的作用是在文件系统中创建⼀一个文件,该文件⽤用于提供FIFO功能,即命名管道。 前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说, 匿名管道是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信。⽽命名管道是一个可见的⽂文件,因此,它可以用于任何两个进程之间的通信,不管这两个进程是不是⽗子进程,也不管这两个进程之间有没有关系。
FIFO read端:
FIFOwrite端:
在这里,提出命名管道的概念FIFO,可解决无名管道的局限性,命名管道到底是通过什么机制进行通信的?请看下面
命名管道(FIFO)
————顾名思义,first input first output,按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
1.概念
管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管 道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO 相互通信。
2.命名管道的创建与读写
Linux下有两种⽅方式创建命名管道。一是在Shell下交互地建立一个命名管道;
二是在程序中使⽤用系统函数建⽴立命名管道。Shell⽅方式下可使⽤用mknod或mkfifo命令。
下⾯面命令使⽤用 mknod创建了⼀一个命名管道:
<span style="font-size:14px;">mknod namedpipe </span>
创建命名管道的系统函数有两个:mknod和mkfifo。
两个函数均定义在头⽂文件sys/stat.h, 函数原型如下:
<span style="font-size:14px;">#include <sys/types.h> #include <sys/stat.h> int mknod(const char *path,mode_t mod,dev_t dev); int mkfifo(const char *path,mode_t mode); </span>
函数mknod参数中path为创建的命名管道的全路径名:mod为创建的命名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。
mknod和mkfifo两个函数调用成功都返回0,失败都返回 -1。
下面使用mknod函数创建了⼀个命名管道:
<span style="font-size:14px;">umask(0) if (mknod("/tmp/fifo",S_IFIFO | 0666) == -1) { perror("mkfifo error"); exit(1); } </span>
函数mkfifo前两个参数的含义和mknod相同下面是使用mkfifo的示例代码:
<span style="font-size:14px;">umask(0); if (mkfifo("/tmp/fifo",S_IFIFO|0666) == -1) { perror("mkfifo error!"); exit(1); } </span>
S_IFIFO|0666 指明创建一个命名管道且存取权限为0666,即创建者,与创建者同组的用户,其他用户对该命名管道的访问权限都是可读可写(注意umask对生成的管道文件权限的影响)
命名管道创建后就可以使⽤用了,命名管道和管道的使用方法基本是相同的。只是使用命 名管道时,必须先调⽤用open()将其打开。因为命名管道是一个存在于硬盘上的文件,而管道 是存在于内存中的特殊文件。
注意,调用open()打开命名管道的进程可能会被阻塞。但如果同时用读写方式 (O_RDWR)打开,则一定不会导致阻塞;如果以只读方式(O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写方打开管道;同样以写方式(O_WRONLY)打开也会阻塞直到有读方式打开管道。
三.总结
文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识⼀一 个IPC通道。 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似。 由于Linux中所有的事物都可被视为⽂文件,所以对命名管道的使用也就变得与文件操作非常的统⼀,也使它的使用非常方便,同时我们也可以像平常的文件名⼀样在命令中使用。
创建命名管道可以用两个函数,函数原型如下:
<span style="font-size:14px;">#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *filename, mode_t mode); int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0); </span>
这两个函数都能创建⼀一个FIFO文件,注意是创建⼀一个真实存在于文件系统中的文件, filename指定了文件名,而mode则指定了文件的读写权限。mknod是比较老的函数,而使用 mkfifo函数更加简单和规范,所以建议在可能的情况下,尽量使用mkfifo而不是mknod。 mkfifo函数的作用是在文件系统中创建⼀一个文件,该文件⽤用于提供FIFO功能,即命名管道。 前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说, 匿名管道是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信。⽽命名管道是一个可见的⽂文件,因此,它可以用于任何两个进程之间的通信,不管这两个进程是不是⽗子进程,也不管这两个进程之间有没有关系。
FIFO read端:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #define _PATH_ "/tmp/file.tmp" #define _SIZE_ 100 int main() { int fd = open(_PATH_, O_RDONLY); if(fd < 0) { printf("open file error!\n"); return 1; } char buf[_SIZE_]; memset(buf, '\0', sizeof(buf)); while(1) { int ret = read(fd, buf, sizeof(buf)); if (ret <= 0)//error or end of file { printf("read end or error!\n"); break; } printf("%s\n", buf); if( strncmp(buf, "quit", 4) == 0 ) { break; } } close(fd); return 0; }
FIFOwrite端:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #define _PATH_ "/tmp/file.tmp" #define _SIZE_ 100 int main() { int ret = mkfifo(_PATH_,0666|S_IFIFO); if(ret == -1) { printf("mkfifo error\n"); return 1; } int fd = open(_PATH_, O_WRONLY); if(fd < 0) { printf("open error\n"); } char buf[_SIZE_]; memset(buf, '\0', sizeof(buf)); while(1) { scanf("%s", buf); int ret = write(fd, buf, strlen(buf)+1); if(ret < 0) { printf("write error\n"); break; } if( strncmp(buf, "quit", 4) == 0 ) { break; } } close(fd); return 0; }
相关文章推荐
- Linux GCC常用命令
- Linux安装JDK配置环境参数变量
- linux服务器分区因挂载问题突然变只读的解决方法
- Linux man命令的使用方法
- CentOS下mysql数据库常用命令总结
- centos中命令自动补全
- CentOS 6.5 安装VNC
- 【转载】GPT 和 Linux
- CentOS学习:第一天
- iTOP 4412安装嵌入式linux编译环境
- centos rar安装
- centos7防火墙 启动和关闭
- linux debian 时间设置中无法选择“自动设定时间和日期”
- 关于Linux的一些常用命令
- linux日志
- 嵌入式 Linux 系统移植——BSP分析
- linux 运行run文件
- Linux管道和过滤器
- linux下mysql的root密码忘记解决方法
- opensuse linux下内核编译方法详解