TCPIP 网络编程-12-IPC-FIFO

FIFO也叫命名管道,与管道类似,最大的差别在于 FIFO 在文件系统中拥有一个名称,打开方式与普通文件一样。这样就能够将 FIFO 用于非相关进程之间的通信(如客户端和服务器)

FIFO特点

  1. 与管道一样,也是字节流

  2. 与管道一样,FIFO 也有一个写入端和读取端,并且从管道中读取数据的顺序与写入的顺序是一样的

  3. 与管道一样,当所有引用 FIFO 的描述符都被关闭之后,所有未被读取的数据会被丢弃

  4. FIFO是双向通信的,允许两个进程在同一个FIFO文件中进行读写操作

  5. 一旦 FIFO 被创建,任何进程都能够打开它,只要它能够通过常规的文件权限检测

  6. 使用 open(path, O_RDONLY) 标记,打开 FIFO 以便读取数据,将会阻塞直到另一个进程打开 FIFO 以写入数据为止。相应地,打开一个 FIFO 以写入数据将会阻塞直到另一个进程打开 FIFO 以读取数据为止,虽然 O_RDWR 可以绕开FIFO阻塞行为,但是不要用

    • 虽然使用 open(path, O_RDWR)就会立即返回,但无法使用返回的文件描述 符在 FIFO 上读取和写入数据。SUSv3 明确指出以 O_RDWR 标记打开一个 FIFO 的结果是未知的,因此出于可移植性的原因,开发人员不应该使用这项技 术。可改为O_NONBLOCK 标记替代
    • 使用 O_RDWR 调用 open() 之后,调用进程在从返回的文件描述符中读取数据时永远都不会看到文件结束,因为永远都至少存在一个文件描述符被打开着以等待数据被写入 FIFO,即进程从中读取数据的那个描述符。

使用命令 $ mkfifo [-m mode] pathname 构建FIFO,当使用 ls –l 列出文件时,FIFO 文件在第一列的类型为 p,ls –F 会在 FIFO 路径名后面附加上一个管道符(|)。

1
2
3
drwxrwxrwx 30      777 root      4096 Feb 29 08:02 directory
-rwxrwxrwx 1 yuankang yuankang 4716 Sep 21 01:01 file
prw-r--r-- 1 root root 0 Mar 7 04:44 hello #管道

使用程序构建FIFO

1
2
3
4
5
6
7
8
9
#include <sys/stat.h>

/**
* @brief 创建一个名为 pathname 的全新的 FIFO
* @param pathname 管道路径
* @param mode 参数指定了新 FIFO 的权限
* @return 0 success; -1 failed
* */
int mkfifo(const char *pathname, mode_t mode);

双重管道线

tee 命令,它将其从标准输入中读取到的数据 复制两份并输出:一份写入到标准输出,另一份写入到通过命令行参数指定的文件中。

1
2
3
$ mkfifo hello
$ wc -l < hello &
$ ls -l | teel hello | sort -k5n

image-20240307125729988

ls -l:这部分是一个ls命令,带有-l选项,表示以长格式(详细信息)显示当前目录中的文件和文件夹列表。

sort -k5n:这部分是对ls -l命令的输出进行排序。sort命令用于对文本文件中的行进行排序,-k5n表示按照第5列的数值(文件大小)进行排序,n代表按照数字顺序排序

CS服务

为了实现多客户端与服务端的通信

  1. 虽然 FIFO 是双向的,但是当接收服务端响应的时候,一个 FIFO 会在多个客户端之间发生竞争。所以每一个进程创建一个 FIFO 用来接收消息。那样一个服务器也只需要一个 FIFO
  2. 服务端收到多个客户端的消息之后,如何给客户端响应。就需要在消息中带上客户端的管道名称
  3. 由于 FIFO 也是字节流,所以需要指定消息的长度,这里使用 proto 进行消息传输

于是就有了示例代码 network-ip/apps/ipcs/02

服务端运行结果:

1
2
3
4
5
[root]#./fifo_svr 
[server/server.c:45 main info] recv client request ./client_fifo_file_0 22
[server/server.c:61 main info] write finished
[server/server.c:65 main info] child exit
[server/server.c:73 main info] parent exit

客户端运行结果:

1
2
3
4
5
[root]#./fifo_cli 
[client/client.c:74 main info] send fifo :./client_fifo_file_0 22
[client/client.c:50 main info] child recv hello world
[client/client.c:56 main info] child exit
[client/client.c:82 main info] parent exit

参考文档

  1. 《UNIX 网络编程卷 2》
  2. 《UNIX 系统编程 44 章》