为什么要通信
通信是进程间交互信息的一种方式。在多进程环境中,进程之间可能需要共享数据或协调工作。通信可以使得进程之间能够交换信息,从而实现更复杂的任务。
以下是一些常见的通信场景:
1.数据共享:多个进程可能需要共享一些数据。例如,一个进程可能需要读取另一个进程写入的数据,或者一个进程可能需要向另一个进程发送一些数据。
2.协调工作:多个进程可能需要协同工作,例如一个进程可能需要等待另一个进程完成某些任务后才能继续执行。
3.事件通知:一个进程可能需要通知另一个进程发生了某些事件,例如一个进程可能需要通知另一个进程某个任务已经完成。
4.资源管理:多个进程可能需要共享一些资源,例如文件、网络连接等。通信可以使得进程之间能够协调地使用这些资源。
匿名管道是什么
匿名管道是一种最基本的进程间通信(IPC)机制,它允许一个进程向另一个进程发送数据。匿名管道只能用于具有亲缘关系的进程之间,即父子进程之间。匿名管道是半双工的,即数据只能在一个方向上流动。
创建匿名管道的过程
匿名管道的创建和操作可以通过以下步骤完成:
创建管道:使用pipe()函数创建一个匿名管道。pipe()函数返回一个包含两个文件描述符的元组,其中第一个文件描述符用于读,第二个文件描述符用于写。
创建子进程:使用fork()函数创建一个子进程。子进程会继承父进程的所有文件描述符,包括管道的文件描述符。
父进程和子进程分别关闭不需要的文件描述符:父进程关闭管道的写端,子进程关闭管道的读端。
父进程向管道写入数据:父进程通过管道的写端写入数据。
子进程从管道读取数据:子进程通过管道的读端读取数据。
关闭管道:父进程和子进程都关闭管道的文件描述符,以释放资源
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
// 父进程进行读取,子进程进行写入
int main()
{
// 第一步:创建管道文件,打开读写端
int fds[2];
int n = pipe(fds);
assert(n == 0);
// 第二步: fork
pid_t id = fork();
assert(id >= 0);
if (id == 0)
{
// 子进程进行写入
close(fds[0]);
// 子进程的通信代码
const char *s = "我是子进程,我正在给你发消息";
int cnt = 0;
while (true)
{
cnt++;
char buffer[1024]; // 只有子进程能看到!
snprintf(buffer, sizeof buffer, "child->parent say: %s[%d][%d]", s, cnt, getpid());
write(fds[1], buffer, strlen(buffer));
cout << "count: " << cnt << endl;
}
// 子进程
close(fds[1]); // 子进程关闭写端fd
cout << "子进程关闭自己的写端" << endl;
// sleep(10000);
exit(0);
}
// 父进程进行读取
close(fds[1]);
// 父进程的通信代码
while (true)
{
sleep(2);
char buffer[1024];
ssize_t s = read(fds[0], buffer, sizeof(buffer) - 1);
if (s > 0)
{
buffer[s] = 0;
cout << "Get Message# " << buffer << " | my pid: " << getpid() << endl;
}
else if(s == 0)
{
cout << "read: " << s << endl;
break;
}
break;
}
close(fds[0]);
cout << "父进程关闭读端" << endl;
int status = 0;
n = waitpid(id, &status, 0);
assert(n == id);
cout <<"pid->"<< n << " : "<< (status & 0x7F) << endl;
return 0;
}