前言:
目录
进程间通信(Inter-process communication,IPC)是指操作系统中不同进程之间进行数据交换和通信的机制。
进程间通信(IPC)的发展一直与计算机领域的进步和需求密切相关。随着计算机技术的不断发展,IPC也经历了许多演进和改进,以满足不断增长的通信需求。以下是进程间通信发展的一些关键方面:
下面是几种常见的进程间通信机制:
这些进程间通信机制各有优缺点,选择合适的机制取决于应用程序的需求和特点。开发者需要考虑数据传输的速度、数据大小、并发性、可靠性等因素来选择适当的通信机制。
管道通信是消息传递的一种特殊方式(见下图):
【解释说明】
【解释说明】
【解释说明】
在Linux中,管道是一种用于进程间通信的特殊机制。根据使用方式和功能,Linux中的管道可以分为不同类型:
匿名管道(Anonymous Pipes): 匿名管道是最基本的管道类型,在命令行中使用竖线符号(|)来创建。它只能用于相关进程之间的通信,父进程与子进程之间或者同一管道链中的进程之间。
命名管道(Named Pipes): 命名管道(也称为FIFO)是一种有名字的管道,由mkfifo命令创建。它可以在磁盘上持久存在,并允许无关的进程之间进行通信。多个进程可以通过读取和写入相同的命名管道来进行数据交换。
匿名管道是一种在进程间进行通信的机制,通常用于父子进程之间或者通过衍生的进程之间传递数据。匿名管道是一种单向通信机制,即数据只能从一个进程流向另一个进程。
💨?接下来介绍匿名管道的一些关键特性:
1??创建匿名管道(大家可以通过man手册进行查询)
pipe
函数)创建;2??下面是一个简单的C语言示例,演示了如何使用匿名管道在父子进程之间进行通信:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 25
int main() {
int pipefd[2]; // 用于存放管道两端文件描述符的数组
pid_t pid;
char message[BUFFER_SIZE] = "Hello, child process!";
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
// 创建子进程
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0) { // 父进程
close(pipefd[0]); // 关闭用于读的文件描述符
// 向管道写入消息
write(pipefd[1], message, strlen(message) + 1);
// 关闭用于写的文件描述符
close(pipefd[1]);
printf("Parent process: Message sent to child.\n");
} else { // 子进程
close(pipefd[1]); // 关闭用于写的文件描述符
// 从管道读取消息
char received_message[BUFFER_SIZE];
read(pipefd[0], received_message, sizeof(received_message));
// 关闭用于读的文件描述符
close(pipefd[0]);
printf("Child process: Received message - %s\n", received_message);
}
return 0;
}
💨当读的一方?read 完所有的管道数据,如果写的一方不往管道里面发送数据,此时就只能等待:
int main()
{
// 任何一种任何一种进程间通信中,一定要 先 保证不同的进程之间看到同一份资源
int pipefd[2] = {0};
//1. 创建管道
int n = pipe(pipefd);
if(n < 0)
{
std::cout << "pipe error, " << errno << ": " << strerror(errno) << std::endl;
return 1;
}
std::cout << "pipefd[0]: " << pipefd[0] << std::endl; //
std::cout << "pipefd[1]: " << pipefd[1] << std::endl; //
//2. 创建子进程
pid_t id = fork();
assert(id != -1); //正常应该用判断,我这里就断言:意料之外用if,意料之中用assert
if(id == 0) // 子进程
{
//3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入
close(pipefd[0]);
//4. 开始通信 -- 结合某种场景
const std::string namestr = "hello, 我是子进程";
int cnt = 1;
char buffer[1024];
while(true)
{
snprintf(buffer, sizeof buffer, "%s, 计数器: %d, 我的PID:
%d",namestr.c_str(), cnt++, getpid());
write(pipefd[1], buffer, strlen(buffer));
sleep(10);
}
close(pipefd[1]);
exit(0);
}
//父进程
//3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入
close(pipefd[1]);
//4. 开始通信 -- 结合某种场景
char buffer[1024];
while(true)
{
int n = read(pipefd[0], buffer, sizeof(buffer) - 1);
if(n > 0)
{
buffer[n] = '\0';
std::cout << "我是父进程, child give me message: " << buffer << std::endl;
}
}
close(pipefd[0]);
return 0;
}
💨当写的一方不往管道里面 write 数据,而读的一方此时不读,当管道写满之后就不能在继续写数据(即管道有大小限制):
输出结果:
?
💨当此时关闭了写数据的一方,读取完毕管道数据。如果在继续读取的话,就会 read 返回0,表明读到文件结尾。
输出结果:
?
💨当写端一直写,读端关闭,此时就没有意义,OS不会维护无意义、低效率的事件,会通过 13号?信号来杀死一直写入的进程:
输出结果:
通过上述,简单总结一下管道有哪些特点:
接下来,简单总结一下本期关于“匿名管道”的全部知识!!!
以上便是本期关于匿名管道的全部内容了,感谢大家的观看与支持!!!
?