52-有名管道

有名管道打破了无名管道的限制,进化出了一个实实在在的 FIFO 类型的文件。这意味着即使没有亲缘关系的进程也可以互相通信了。所以,只要不同的进程打开 FIFO 文件,往此文件读写数据,就可以达到通信的目的。

不过 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 14 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.

ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. Or, the file is a device special file and no corresponding device exists.

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 发送端或者接收端任何一个进程,观察程序运行结果,并验证你的观点。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值