52-有名管道
2017-01-04 11:30
148 查看
有名管道打破了无名管道的限制,进化出了一个实实在在的 FIFO 类型的文件。这意味着即使没有亲缘关系的进程也可以互相通信了。所以,只要不同的进程打开 FIFO 文件,往此文件读写数据,就可以达到通信的目的。
不过 FIFO 文件与我们最开始讲的本地文件通信还是有着本质的区别,它长着普通文件的脑袋,却有着无名管道的基因。
如:
通过函数 mkfifo(3) 创建
比如:
该函数返回 0 表示成功,-1 失败。
某些版本的系统在 hello 文件后面还会跟着个
接下来你的 cat 命令被阻塞住。
开启另一个终端,执行:
然后你会看到被阻塞的 cat 又继续执行完毕,在屏幕打印 “hello world”。如果你反过来执行上面两个命令,会发现先执行的那个总是被阻塞。
文件属性前面标注的文件类型是 p,代表管道
文件大小是 0
fifo 文件需要有读写两端,否则在打开 fifo 文件时会阻塞
当然了,如果在 open 的时候,使用了非阻塞方式,肯定是不会阻塞的。特别地,如果以非阻塞写的方式 open,同时没有进程为该文件以读的方式打开,会导致 open 返回错误(-1),同时 errno 设置成 ENXIO.
因为 recv 端还没打开 hello 文件,这时候 send 是阻塞状态的。
再开启另一个终端:
这时候 send 端和 recv 端都在终端显示
此时在 send 端输入数据,recv 打印。
![](http://img.blog.csdn.net/20170104112736964?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcTEwMDc3Mjk5OTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
图1 运行结果
知道 fifo 文件的特性
练习:kill 发送端或者接收端任何一个进程,观察程序运行结果,并验证你的观点。
不过 FIFO 文件与我们最开始讲的本地文件通信还是有着本质的区别,它长着普通文件的脑袋,却有着无名管道的基因。
1. 创建 FIFO 类型文件
通过命令 mkfifo 创建如:
$ mkfifo hello
通过函数 mkfifo(3) 创建
int mkfifo(const char *pathname, mode_t mode);
比如:
mkfifo("hello", 0664);
该函数返回 0 表示成功,-1 失败。
2. FIFO 文件的特性
2.1 查看文件属性
当使用 mkfifo 创建 hello 文件后,查看文件信息如下:prw-rw-r-- 1 allen allen 0 1月 4 09:57 hello
某些版本的系统在 hello 文件后面还会跟着个
|符号,像这样
hello|
2.2 使用 cat 命令打印 hello 文件内容
$ cat hello
接下来你的 cat 命令被阻塞住。
开启另一个终端,执行:
$ echo "hello world" > hello
然后你会看到被阻塞的 cat 又继续执行完毕,在屏幕打印 “hello world”。如果你反过来执行上面两个命令,会发现先执行的那个总是被阻塞。
2.3 fifo 文件特性
根据前面两个实验,可以总结:文件属性前面标注的文件类型是 p,代表管道
文件大小是 0
fifo 文件需要有读写两端,否则在打开 fifo 文件时会阻塞
当然了,如果在 open 的时候,使用了非阻塞方式,肯定是不会阻塞的。特别地,如果以非阻塞写的方式 open,同时没有进程为该文件以读的方式打开,会导致 open 返回错误(-1),同时 errno 设置成 ENXIO.
3. 实例
下面有两个程序,分别是发送端 send 和接收端面 recv。程序 send 从标准输入接收字符,并发送到程序 recv,同时 recv 将接收到的字符打印到屏幕。3.1 发送端
// send.c #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { char buf[64]; int n = 0; int fd = open("hello", O_WRONLY); if (fd < 0) { perror("open fifo"); return -1;} puts("has opend fifo"); while((n = read(STDIN_FILENO, buf, 64)) > 0) { write(fd, buf, n); if (buf[0] == 'q') break; } close(fd); return 0; }
3.2 接收端
// recv.c #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { char buf[64]; int n = 0; int fd = open("hello", O_RDONLY); if (fd < 0) { perror("open fifo"); return -1;} puts("has opened fifo"); while((n = read(fd, buf, 64)) > 0) { write(STDOUT_FILENO, buf, n); } if (n == 0) { puts("remote closed"); } else { perror("read fifo"); return -1; } close(fd); return 0; }
3.3 编译
$ gcc send.c -o send $ gcc recv.c -o recv
3.4 运行
$ ./send
因为 recv 端还没打开 hello 文件,这时候 send 是阻塞状态的。
再开启另一个终端:
$ ./recv
这时候 send 端和 recv 端都在终端显示
has opend fifo
此时在 send 端输入数据,recv 打印。
图1 运行结果
4. 总结
掌握如果创建 fifo 文件知道 fifo 文件的特性
练习:kill 发送端或者接收端任何一个进程,观察程序运行结果,并验证你的观点。
相关文章推荐
- 进程间通讯-有名管道
- 进程间通信(IPC)2 ------ 有名管道
- linux无名管道和有名管道
- Linux有名管道编程
- Linux环境进程间通信:管道及有名管道
- 有名管道通讯
- [国嵌攻略][081][有名管道通讯]
- 记录下python的有名管道通信
- Linux环境进程间通信(一):管道及有名管道
- Linux环境进程间通信(一) 管道及有名管道
- Linux有名管道namepipe --C和Python两种实现方式解析
- Linux进程间的通信——有名管道fifo与守护进程deamon
- [Linux C编程]有名管道实现守护进程
- 【转】Linux进程间通信——管道及有名管道
- 有名管道
- Linux 进程间通讯之有名管道方式
- 进程守护+有名管道+无名管道
- 管道(pipe)和有名管道(fifo)
- 有名管道
- 进程间通信IPC之--无名管道(pipe)和有名管道(fifo)(转)