管道通信是 Linux 中的一种进程间通信(IPC)机制,它允许一个进程将数据传输给另一个进程。管道通常用于父子进程或兄弟进程之间的通信。在 Linux 中,管道有两种主要类型:
无名管道(Unnamed Pipe)
有名管道(Named Pipe,FIFO)
1. 无名管道通信
无名管道是最常见的一种形式,它通常在父子进程之间进行通信。无名管道没有名字,且仅在创建它的进程的父子关系中有效。
使用无名管道的基本步骤:
创建管道:使用
pipe()系统调用创建一个管道。该调用会返回两个文件描述符:一个用于读操作,一个用于写操作。使用
fork()创建子进程:父进程通过fork()创建子进程,父子进程可以共享管道。读写数据:父进程将数据写入管道,子进程从管道读取数据。
示例代码:
以下是一个使用无名管道的简单示例,父进程向子进程发送消息:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main() {int pipefd[2];pid_t pid;char buffer[128];// 创建管道if (pipe(pipefd) == -1) {perror("pipe");exit(1);}pid = fork(); // 创建子进程if (pid == -1) {perror("fork");exit(1);}if (pid > 0) { // 父进程close(pipefd[0]); // 关闭管道的读端const char *msg = "Hello from parent!";write(pipefd[1], msg, strlen(msg) + 1); // 向管道写入数据close(pipefd[1]); // 关闭写端} else { // 子进程close(pipefd[1]); // 关闭管道的写端read(pipefd[0], buffer, sizeof(buffer)); // 从管道读取数据printf("Child process received: %s\n", buffer);close(pipefd[0]); // 关闭读端}return 0;
}
解释:
pipe():创建一个管道,
pipefd[0]为读端,pipefd[1]为写端。fork():创建子进程,父子进程可以共享管道文件描述符。
父进程:向管道的写端写入数据。
子进程:从管道的读端读取数据。
2. 有名管道通信(FIFO)
有名管道是另一种管道类型,它与无名管道的区别在于,它有一个名称,并且可以在不同的进程之间共享。由于有名管道在文件系统中有一个路径,因此任何进程都可以通过该路径访问它。
使用有名管道的基本步骤:
创建有名管道:使用
mkfifo()创建有名管道文件。打开管道:使用
open()打开管道文件。读写数据:通过管道文件描述符进行数据读写操作。
删除管道:当管道不再需要时,使用
unlink()删除有名管道。
示例代码:
创建有名管道进行通信的两个程序示例,分别是写入程序和读取程序。
1. 写入程序(writer.c):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>#define FIFO_NAME "/tmp/myfifo"int main() {int fd;const char *msg = "Hello from writer!";// 创建有名管道if (mkfifo(FIFO_NAME, 0666) == -1) {perror("mkfifo");exit(1);}// 打开管道进行写入fd = open(FIFO_NAME, O_WRONLY);if (fd == -1) {perror("open");exit(1);}// 向管道写入数据write(fd, msg, strlen(msg) + 1);close(fd); // 关闭管道return 0;
}
2. 读取程序(reader.c):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>#define FIFO_NAME "/tmp/myfifo"int main() {int fd;char buf[128];// 打开管道进行读取fd = open(FIFO_NAME, O_RDONLY);if (fd == -1) {perror("open");exit(1);}// 从管道读取数据read(fd, buf, sizeof(buf));printf("Reader received: %s\n", buf);close(fd); // 关闭管道return 0;
}
解释:
mkfifo():创建一个名为
/tmp/myfifo的有名管道。writer.c:打开有名管道的写端,向其中写入消息。
reader.c:打开有名管道的读端,读取消息并打印。
注意:
阻塞行为:如果管道没有数据可读,
read()会阻塞,直到有数据可用。反之,写操作会阻塞直到管道有空间可以写入。管道删除:使用
unlink()删除有名管道。
3. 管道的总结:
无名管道:适用于父子进程之间的单向通信,通信是匿名的。
有名管道:适用于不同进程之间的通信,并且它在文件系统中有一个路径,可以被其他进程访问。
通过管道通信,进程可以有效地交换数据。管道是 Linux 系统中一个非常重要的 IPC 机制,广泛用于多进程之间的数据传输。