C++进程间通信 匿名管道和命名管道
- [1. 匿名管道](#1. 匿名管道)
- [2. 命名管道](#2. 命名管道)
匿名管道适用于父子进程之间的简单通信,而命名管道则适用于无亲缘关系的进程之间的通信。
1. 匿名管道
匿名管道概述
匿名管道是用于在具有亲缘关系的进程(如父子进程)之间进行单向通信的简单方式。管道创建时包含两个文件描述符:一个用于读(读端),一个用于写(写端)。
匿名管道代码示例
cpp
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
int main()
{
int pipefd[2]; // 用于保存管道文件描述符
pid_t cpid;
char buf;
if (pipe(pipefd) == -1)
{ // 创建管道
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork(); // 创建子进程
if (cpid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{ // 子进程
close(pipefd[1]); // 关闭写端
while (read(pipefd[0], &buf, 1) > 0)
{
write(STDOUT_FILENO, &buf, 1); // 读取管道并输出到标准输出
}
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]); // 关闭读端
_exit(EXIT_SUCCESS);
}
else
{ // 父进程
close(pipefd[0]); // 关闭读端
const char *msg = "Hello from parent process!";
write(pipefd[1], msg, strlen(msg)); // 写入管道
close(pipefd[1]); // 关闭写端
wait(NULL); // 等待子进程结束
exit(EXIT_SUCCESS);
}
}
代码解释
- 管道创建 :
pipe(pipefd)
创建一个匿名管道,其中pipefd[0]
是读端,pipefd[1]
是写端。 - 进程创建 :
fork()
创建一个子进程。cpid
在子进程中为0,在父进程中为子进程ID。 - 子进程 :
- 关闭写端。
- 读取管道数据并输出到标准输出。
- 关闭读端并退出。
- 父进程 :
- 关闭读端。
- 将消息写入管道。
- 关闭写端并等待子进程结束。
运行结果
Hello from parent process!
2. 命名管道
命名管道概述
命名管道(FIFO)是一种特殊的文件,可以用于无亲缘关系的进程之间进行双向通信。它通过在文件系统中创建一个命名管道文件进行通信。
命名管道代码示例
首先,创建一个命名管道文件:
sh
mkfifo /tmp/myfifo
然后,编写两个程序,一个用于写入数据,另一个用于读取数据。
写入数据的程序(writer.cpp)
cpp
#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
int main()
{
const char *fifo = "/tmp/myfifo";
int fd = open(fifo, O_WRONLY); // 打开命名管道的写端
if (fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
const char *msg = "Hello from writer process!";
write(fd, msg, strlen(msg)); // 写入数据到命名管道
close(fd); // 关闭管道
return 0;
}
读取数据的程序(reader.cpp)
cpp
#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
int main()
{
const char *fifo = "/tmp/myfifo";
char buf[128];
int fd = open(fifo, O_RDONLY); // 打开命名管道的读端
if (fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
ssize_t numBytes = read(fd, buf, sizeof(buf)); // 从管道读取数据
if (numBytes > 0)
{
buf[numBytes] = '\0';
std::cout << "Received message: " << buf << std::endl; // 输出读取的数据
}
close(fd); // 关闭管道
return 0;
}
代码解释
- 创建命名管道文件 :通过
mkfifo
命令在文件系统中创建一个命名管道文件。 - 写入数据的程序(writer.cpp) :
- 打开命名管道的写端。
- 将消息写入管道。
- 关闭管道。
- 读取数据的程序(reader.cpp) :
- 打开命名管道的读端。
- 从管道读取数据。
- 输出读取的数据。
- 关闭管道。
运行步骤
-
在终端中创建命名管道文件:
shmkfifo /tmp/myfifo
-
分别编译
writer.cpp
和reader.cpp
:shg++ writer.cpp -o writer g++ reader.cpp -o reader
-
打开两个终端,在第一个终端运行读取程序:
sh./reader
-
在第二个终端运行写入程序:
sh./writer
运行结果
第一个终端(运行读取程序)输出:
Received message: Hello from writer process!