一、进程间通信的前提条件
两个不同的进程之间想要进行通信,就必须让这两个进程看到同一份文件。在Linux中,不同的进程可以通过管道来进行数据的交互。
二、匿名管道的认识
在linux中,管道用来进行进程间通信的形式,其中有匿名管道和命名管道。
匿名管道不是一个单独的文件,没有属于自己的inode,因此被创建后只有当前进程可以看到,因此当我们进行匿名管道间的通信的,大多都是通过父子进程实现的,因为子进程通过继承父进程的资源(包括文件描述符表),进而可以看到在父进程中创建的匿名管道。
父进程中有属于其自己的文件描述符表,其中0,1,2号文件描述符默认打开,分别是stdin,stdout,stderr。而管道也有着自己的两个文件描述符,对应一个读端一个写端,从而进行单项传输,当我们的父进程创建管道时,父进程的文件描述符表情况如下图:
假设管道的两个文件描述符为fd[0]与fd[1],我们默认fd[0]为R端(读端),fd[1]为W端(写端)
假设我们需要父进程向子进程发送数据,子进程只需要读父进程写的数据(这也是管道最开始的用途,只是最简单的单向通信,因此我们的管道应该只有一个读端一个写端),所以子进程应该关闭子进程文件描述符表中对管道的写端,父进程应该关闭父进程文件描述符表中对管道的读端,所以父进程与子进程的文件描述符表对应管道的读写端应该如下图所示:
三、父子进程通过匿名管道进行通信的代码实现
这里以父进程读子进程,子进程往父进程写
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
using namespace std;
// 匿名管道的实现
int main()
{
// 创建管道,将fds[0]设置成R端,fds[1]设置成W端
int fds[2] = {0};
int n = pipe(fds);
if (n != 0)
{
cerr << "pipe" << endl;
exit(1);
}
// 创建子进程
pid_t id = fork();
if (id < 0)
{
cerr << "fork()" << endl;
exit(1);
}
// 子进程
if (id == 0)
{
// 关闭不需要的文件描述符,子往父写,关闭子的读->0
close(fds[0]);
while (1)
{
string msg = "Helloworld";
int pid = getpid();
int ppid = getppid();
cout<<"我是子进程,我的Pid是:"<<pid<<" 我的父进程Pid:"<<ppid <<endl;
write(fds[1], msg.c_str(), msg.size());
sleep(3);
}
exit(0);
}
else
{
// 父进程读子进程,关闭父进程的写
close(fds[1]);
char buffer[1024]; // 缓冲区
while (1)
{
ssize_t n = read(fds[0], buffer, 1024);
if (n > 0)
{
buffer[n] = 0;
int pid = getpid();
cout << "我是父进程,pid:" << pid << " ";
cout << "child -> father, msg:" << buffer << endl;
}
}
exit(0);
}
return 0;
}
运行pipe文件,通过打印出来的结果可知,我们已经成功实现父子进程通过匿名管道进行通信了