进程间通信(一)
简而言之就是操作系统为上层提供的进程间通信的方式
为什么要操作系统提供呢?
每个进程具有独立性,每个进程访问的都是自己的虚拟地址空间的虚拟地址
因此需要操作系统提供一个进程间都可访问的区域来实现通信
因为应用场景不同,因此提供的方式也多种多样
管道
管道 :用于实现进程间的数据传输功能
本质就是内核中的一块缓冲区
管道的种类 :匿名管道和命名管道
1. 匿名管道
:
概念:在内核中申请一块固定大小的缓冲区,程序拥有写入和读取的权利,一般使用fork函数实现父子进程的通信。
(1)在内核中创建管道
#include <unistd.h>
int pipe(int pipefd[2]); // 返回值:若成功返回0,失败返回-1
(2)创建成功则返回管道的操作句柄
(3)操作方式类似于文件操作
父进程创建管道,得到两个⽂件描述符指向管道的两端
父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。
(4)pipefd[0] pipefd[1] 对应两个操作句柄,一个用于读取数据,一个用于写入数据
父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。
2.管道的特性
管道是半双工通信
管道自带同步与互斥
互斥:写操作不超过PIPE_BUF大小(4096字节),保证原子性,保证安全操作
同步:管道中没有数据,read会堵塞,缓冲区满,write会堵塞
管道提供字节流服务:有序的(先进先出),可靠的,不限制传输大小,基于连接的
若所有读端关闭,则写入异常,导致进程退出
若所有写端关闭,则读完数据不会阻塞,返回0
管道的生命周期随进程,进程关闭则释放
管道符 : |
连接两个命令,把前面命令的输出结果交给后面的命令处理
ps -ef | grep ssh
ps进程和ssh进程通过匿名管道进行数据传输
实现原理:
创建管道和两个子进程,ps输出到标准输出(1),grep从标准输入(0)拿数据,只需要把1重定向到管道的写,把0重定向到管道的读,这时候写入的数据写道管道里,读数据就从管道读数据
上代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) < 0) {
perror("pipe error");
return -1;
}
pid_t ps_pid = fork();
if (ps_pid == 0) {
close(pipefd[0]);
dup2(pipefd[1], 1);
execlp("ps", "ps", "-ef", NULL);
exit(0);
}
pid_t grep_pid = fork();
if (grep_pid == 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
execlp("grep", "grep", "ssh", NULL);
exit(0);
}
close(pipefd[0]);
close(pipefd[1]);
waitpid(ps_pid, NULL, 0);
waitpid(grep_pid, NULL, 0);
return 0;
}
3.命名管道
内核中的缓存区具有标识符,可用于主机上的任意进程间通信
本质上还是缓存区,只是标识符是可见于文件系统的管道文件
缓冲区大小和磁盘空间无关
int ret = mkfifo("./test.fifo", 0664);
if (ret < 0 && errno != EEXIST) {
perror("mkfifo error");
return -1; }
printf("create fifo success!\n");
如果文件已经存在,我们不关注这个错误继续执行
注意此处需要给定权限
返回值:成功返回0,失败返回-1
int fd = open("./test.fifo", O_RDONLY); //以只读方式打开
if (fd < 0) {
perror("open error");
return -1;
}
printf("open success!!\n");
int fd = open("./test.fifo", O_WRONLY); //以只写方式打开
if (fd < 0) {
perror("open error");
return -1;
}
printf("open success!!\n");
4.命名管道的特性
如果命名管道没有被写的方式打开,则只读打开 就会阻塞
如果命名管道没有被读的方式打开,则只写打开 就会阻塞
谢谢大家观看,更多代码请点击下方地址,进入我的的github