1. 管道pipe (无名管道)
本质是一个伪文件,实际为内核缓冲区。由两个文件描述符引用,一个表示读端,一个表示写端,数据单向流动。
原理:管道实为内核使用环形队列机制,借助内核缓冲区(4K)实现。
磁盘读写的单位是一个扇区,大小为512byte,即文件最小为512byte。
局限性:数据自己读不能自己写;数据一旦被读走便不在管道中,不可反复读取;由于管道采用(单向)半双工通信方式,所以数据只能在一个方向上流动;只能在有公共祖先的进程间使用管道(有血缘关系)。
int pipe(int pipefd[2]); --> 创建一个管道,将打开的两个文件描述符(对应管道的两端)放入参数pipefd中。
返回值:成功返回0, 失败返回-1.
pipefd[0] --> 读; pipefd[1] --> 写
读管道:管道中有数据时返回实际读到的字节数;管道中无数据时,如果写端全关闭则返回0,若仍有写端打开则阻塞等待。
写管道:读端全关闭则进程异常终止(SIGPIPE信号);有读端打开时,若管道未满则返回写入字节数,管道已满时阻塞。
2. fifo(命名管道):提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,这样,即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。
fifo和pipe的不同之处:
(1)、FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中。
(2)、当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。
(3)、FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。
int mkfifo(const char* pathname, mode_t mode);
pathname: 普通的路径名,也就是创建后 FIFO 的名字。
mode: 文件的权限,与打开普通文件的 open() 函数中的 mode 参数相同
fifo在open时默认阻塞。open() 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO open() 以只写方式打开 FIFO时,要阻塞到某个进程为读而打开此 FIFO。 简单一句话,只读等着只写,只写等着只读,只有两个都执行到,才会往下执行。如果不想在open时阻塞,可以以可读可写的方式open。
如果FIFO中没有数据,而且有写端打开时,read函数会阻塞,和无名管道相同。如果写进程先退出了,就算命名管道内没有数据,read函数也会不阻塞直接返回0;若写进程又重新运行,则read函数恢复阻塞;
若读进程先退出后,写进程向FIFO中写数据时,写进程会收到SIGPIPE信号退出。
注:一个进程mkfifo,不能同时mkfifo,不然会重复。
程序不能以O_RDWR(读写)模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程就会读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递。
就是传递给open调用的是FIFO的路径名,而不是正常的文件。(如:const char *fifo_name = "/tmp/my_fifo"; )。
第二个参数中的选项O_NONBLOCK,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。
阻塞问题:
对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。
对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。
1 #include <stdio.h> 2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7
8 int main()
9 {
10 int ret = mkfifo("myFifo", 0644);
11 if (ret < 0)
12 {
13 perror("mkfifo");
14 exit(1);
15 }
16 printf("Before open.\n");
17 int fd;
18 if ((fd = open("myFifo", O_RDONLY)) < 0)
19 {
20 perror("open");
21 exit(1);
22 }
23 printf("After open.\n");
24 printf("Going to read.\n");
25 char buf[1024] = { 0 };
26 if ((ret = read(fd, buf, sizeof(buf))) < 0)
27 {
28 perror("read");
29 exit(1);
30 }
31 printf("Read over, %s\n", buf);
32
33 return 0;
34 }
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 int main()
10 {
11 if (access("myFifo", W_OK) == -1)
12 {
13 printf("file not exists.\n");
14 exit(1);
15 }
16 printf("Before open.\n");
17 int fd, ret;
18 if ((fd = open("myFifo", O_WRONLY)) < 0)
19 {
20 perror("open");
21 exit(1);
22 }
23 printf("After open.\n");
24
25 printf("Before write.\n");
26 char* buf = "Hello fifo";
27 if ((ret = write(fd, buf, strlen(buf))) < 0)
28 {
29 perror("write");
30 exit(1);
31 }
32 close(fd);
33
34 return 0;
35 }