有名管道

有名管道FIFO

无名管道只能用于具有亲缘关系的进程之间,这大大的限制了管道的使用,有名管道的出现突破了这种限制,它可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立管道之后,两个进程就可以把它当作普通文件一样进行读写操作。

值得注意的是,FIFO的读总是从开始处返回数据,写则是添加到末尾,不支持lseek()等文件定位操作

有名管道可以使用mkfifo()创建,该函数类似open(),可以指定管道的路径和打开模式

在创建管道成功以后,就可以使用open()、read()和write()这些函数了。与普通文件的开发设置一样,对于为读而打开的管道可以在open()中设置O_RDONLY,对于为写而打开的管道可在open()中设置O_WRONLY,不同的是阻塞问题。在管道的读写中会出现阻塞的可能,这里的非阻塞标志可以在open()中设定为O_NONBLOCK。下面分别对阻塞打开和非阻塞打开的读写进行分析:

对于读进程:

  • 若该管道是阻塞打开,且当前FIFO中没有数据,则对读进程而言将一直阻塞到有数据写入
  • 若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会立即执行读操作。如果没有数据则立即返回0

对于写进程:

  • 若该管道是阻塞打开,则写操作一直阻塞到数据可以写入
  • 若该管道是非阻塞打开而不能写入全部数据,则部分写入或调用失败

mkfifo()

1
2
3
#include <sys/types.h>
#include <sys/state.h>
int mkfifo (const char *filename, mode_t mode);

mode:

O_RDONLY : 读管道

O_WRONLY : 写管道

O_RDWR : 读写管道

O_NONBLOCK : 非阻塞

O_CREAT : 如果不存在则创建,并用第三个参数设置权限

O_EXCL : 如果使用O_CREAT时文件存在,返回错误消息

出错时的errno如下:

erron 描述
EACCESS 参数filename所指定的目录无可执行权限
EEXIST 参数filename所指定的文件已存在
ENAMETOOLONG 参数filename的路径名称太长
ENOENT 参数filename包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数filename路径中的目录存在但却非真正的目录
EROFS 参数filename指定文件存在于只读文件系统内

写管道:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MYFIFO "./myfifo"
#define MAX_BUFFER_SIZE PIPE_BUF

int main(int argc, char *argv[])
{
int fd;
char buf[MAX_BUFFER_SIZE] = {0};
int nwrite;

if (argc <= 1)
{
printf ("Usage: ./fifo_write string\n");
exit(1);
}

sscanf(argv[1], "%s", buf);

fd = open (MYFIFO, O_WRONLY);
if (fd == -1)
{
printf ("Open fifo file error\n");
exit(1);
}

if ((nwrite = write (fd, buf, MAX_BUFFER_SIZE)) > 0)
{
printf ("Write '%s' to FIFO\n", buf);
}

close(fd);
exit(0);

}

读管道:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MYFIFO "./myfifo"
#define MAX_BUFFER_SIZE PIPE_BUF

int main()
{
int fd;
char buf[MAX_BUFFER_SIZE] = {0};
int nwrite;

if (access(MYFIFO, F_OK) == -1)
{
if ((mkfifo (MYFIFO, 0666) < 0) && (errno != EEXIST))
{
printf ("Cannot creat fifo file\n");
exit(1);
}
}

fd = open (MYFIFO, O_RDONLY);
if (fd == -1)
{
printf ("Open fifo file error\n");
exit(1);
}

while (1)
{
memset(buf, 0, sizeof (buf));
if ((nwrite = read (fd, buf, MAX_BUFFER_SIZE)) > 0)
{
printf ("Read '%s' from FIFO\n", buf);
}
}

close(fd);
exit(0);

}

有名管道
https://carl-5535.github.io/2021/05/31/Linux系统编程/有名管道/
作者
Carl Chen
发布于
2021年5月31日
许可协议