管道(Pipes)和先进先出(FIFOs,也称为命名管道)都是Linux中用于进程间通信(IPC)的机制。它们允许数据从一个进程流向另一个进程,类似于命令行中的管道操作符 |
。下面详细介绍这两种机制以及如何使用它们。
管道 (Pipes)
管道是一种特殊的文件,它允许数据从一个进程(通常称为生产者)流向另一个进程(通常称为消费者)。管道是半双工的,意味着数据只能单向流动。
特点
- 管道存在于内存中,不是真正的文件系统对象。
- 管道只能用于具有亲缘关系的进程之间,通常是父子进程。
- 管道是半双工的,即数据只能在一个方向上流动。
- 管道的容量有限,当写入的数据超过管道的容量时,写入操作会被阻塞,直到消费者读取了一些数据。
创建管道
- pipe():
int pipe(int pipefd[2])
: 创建一个管道。- 参数
pipefd
是一个数组,包含两个文件描述符,第一个用于读取,第二个用于写入。
示例代码
以下是一个简单的例子,展示了如何使用管道在父子进程中传递数据:
1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <sys/wait.h>
6
7int main() {
8 int pipefd[2];
9 pid_t pid;
10
11 // 创建管道
12 if (pipe(pipefd) == -1) {
13 perror("pipe");
14 exit(EXIT_FAILURE);
15 }
16
17 // 创建子进程
18 pid = fork();
19 if (pid < 0) {
20 perror("fork");
21 exit(EXIT_FAILURE);
22 } else if (pid == 0) { // 子进程
23 close(pipefd[1]); // 关闭写端
24 char buffer[1024];
25 ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
26 if (bytes_read == -1) {
27 perror("read");
28 exit(EXIT_FAILURE);
29 }
30 buffer[bytes_read] = '\0'; // 确保字符串以空字符结尾
31 printf("子进程读取: %s\n", buffer);
32 close(pipefd[0]);
33 exit(EXIT_SUCCESS);
34 } else { // 父进程
35 close(pipefd[0]); // 关闭读端
36 const char *message = "Hello, World!";
37 ssize_t bytes_written = write(pipefd[1], message, strlen(message));
38 if (bytes_written == -1) {
39 perror("write");
40 exit(EXIT_FAILURE);
41 }
42 close(pipefd[1]);
43
44 // 等待子进程结束
45 wait(NULL);
46 }
47
48 return 0;
49}
FIFO (Named Pipes)
FIFO 或命名管道类似于管道,但它们是文件系统中的特殊文件,因此可以被任何进程访问。这意味着它们可以用于没有亲缘关系的进程之间进行通信。
特点
- FIFO 是持久性的,即使创建它的进程不再存在,FIFO 仍然存在。
- FIFO 可以被任何进程打开和使用,而不仅仅是父子进程。
- FIFO 也是半双工的,即数据只能在一个方向上流动。
- FIFO 的容量同样有限,当写入的数据超过 FIFO 的容量时,写入操作会被阻塞,直到消费者读取了一些数据。
创建 FIFO
- mkfifo():
int mkfifo(const char *pathname, mode_t mode)
: 创建一个 FIFO。- 参数
pathname
指定 FIFO 的路径名,mode
指定权限掩码。
示例代码
以下是一个简单的例子,展示了如何使用命名管道在两个进程之间传递数据:
1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <sys/stat.h>
7
8#define FIFO_NAME "/tmp/myfifo"
9
10int main() {
11 int filedes;
12 char buffer[1024];
13
14 // 创建 FIFO
15 if (mkfifo(FIFO_NAME, S_IRUSR | S_IWUSR) == -1) {
16 if (errno != EEXIST) {
17 perror("mkfifo");
18 exit(EXIT_FAILURE);
19 }
20 }
21
22 // 读取进程
23 filedes = open(FIFO_NAME, O_RDONLY);
24 if (filedes == -1) {
25 perror("open");
26 exit(EXIT_FAILURE);
27 }
28
29 ssize_t bytes_read = read(filedes, buffer, sizeof(buffer) - 1);
30 if (bytes_read == -1) {
31 perror("read");
32 exit(EXIT_FAILURE);
33 }
34 buffer[bytes_read] = '\0'; // 确保字符串以空字符结尾
35 printf("读取进程: %s\n", buffer);
36 close(filedes);
37
38 // 写入进程
39 filedes = open(FIFO_NAME, O_WRONLY);
40 if (filedes == -1) {
41 perror("open");
42 exit(EXIT_FAILURE);
43 }
44
45 const char *message = "Hello, World!";
46 ssize_t bytes_written = write(filedes, message, strlen(message));
47 if (bytes_written == -1) {
48 perror("write");
49 exit(EXIT_FAILURE);
50 }
51 close(filedes);
52
53 return 0;
54}
注意事项
- 在使用管道或 FIFO 之前,确保检查文件描述符的有效性。
- 当使用 FIFO 时,确保至少有一个进程已经打开了 FIFO 的读端或写端,否则打开操作可能会失败。
- 在使用完管道或 FIFO 后,记得关闭文件描述符以释放资源。
- 在创建 FIFO 之后,确保在不再需要时删除它以释放文件系统资源。
- 跨进程通信时,确保处理好同步问题,避免数据竞争或死锁。
管道和 FIFO 都是非常有用的进程间通信工具,它们可以简化数据在进程之间的传输过程。理解和熟练掌握这些机制对于编写可靠、高效的多进程程序非常重要。
标签:IPC,read,bytes,FIFO,管道,Linux,进程,include From: https://blog.csdn.net/suifengme/article/details/140753445