✊✊✊🌈本文主要讲解进程间通信方式-管道的相关概念以及通信如何构建,并搭配上实例代码来更好理解进程通信-管道的构建过程。
🎡导航小助手🎡
✨liunx学习篇-进程间通信方式-管道✨
📚一.管道
管道使用起来很简单,主要有无名管道和命名管道两种 。
🌲(1)无名管道(pipe)
int pipe(int pipefd[2]);//创建并打开管道
参数:
pipefd[0]:读端
pipefd[1]:写端
返回值:
成功:0
失败:-1
🌷原理:内核借助了一个循环队列机制,使用内核缓冲区实现
🌷特点:
- 伪文件
- 管道中的数据只能一次读取
- 数据在管道中,只能单向流动(单向半双工)
🌷局限性:
- 自己写,但是不能自己读
- 数据不可以反复读取
- 单向半双工通信
- 血缘关系进程间使用
🌷管道的读写行为:
读管道:
- 管道有数据,read返回实际读到的字节数
- 管道无数据:
(1)无写端,read返回0;
(2)有写端,read阻塞等待;
写管道:
- 无写端,异常终止(SIGPIPE)
- 有读端,
(1)管道已满,阻塞等待;
(2)管道未满,返回写入字节数;
(2)命名管道
🌲(2)命名管道(fifo)
fifo被称为命名管道,pipe用于有血缘关系的进程间通信,fifo,无血缘关系的进程也可以通信。
创建方式有两种:
1.直接通过指令创建mkfifo myfifo
2.通过库函数实现int mkfifo(const char*pathname,mode_t mode);
使用时需要使用open先打开,针对其使用文件IO相关操作
🔑二.实现
🍉1、无名管道(pipe)-父子进程间通讯
子进程负责写入,父进程负责读出。
1.子进程写入时,首先关闭读端pipefd[0],写入字符串str,写完之后关闭写端pipefd[1]。
2.父进程读出时,首先关闭写端pipefd[1],先将数据读入到缓冲区buf中,然后打印,之后关闭写端pipefd[0]。
💻 代码mypipo.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int ret;
int pipefd[2];
ret=pipe(pipefd);//创建并打开管道
char buf[1024];//缓冲区
char*str="hello! i am parent!\n";
if(ret==-1){
perror("pipe error!\n");
exit(1);
}
int pid=fork();//创建子进程
if(pid>1){//子进程
close(pipefd[0]);//close read
write(pipefd[1],str,strlen(str));
close(pipefd[1]);
}else if(pid==0){//父进程
close(pipefd[1]);//close write
ret=read(pipefd[0],buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);//
close(pipefd[0]);
}
return 0;
}
🌻结果展示:
🍉 2、无名管道(pipe)-兄弟进程间通讯
进程间通讯不仅能传输数据,还能传输指令。
指令: ls wc -l 查看当前目录有多少子文件
💻 bropipe.c
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
int main(){
int ret;
int fd[2];
ret=pipe(fd);
if(ret==-1){
perror("pipe error!\n");
exit(1);
}
int i=0;
pid_t pid;
for(;i<2;i++){
pid =fork();
if(pid==-1){
perror("fork error!\n");
exit(1);
}
if(pid==0) break;
}
if(i==2){// parent
close(fd[0]);
close(fd[1]);
wait(NULL);
wait(NULL);
}else if(i==0){//first child
close(fd[0]);//关闭读端
dup2(fd[1],STDOUT_FILENO);//通过文件重定向,将写端重定向到STDOUT_FILENO
execlp("ls","ls",NULL);//
perror("error!\n");//捕获异常
}else if(i==1){//second child
close(fd[1]);
dup2(fd[0],STDIN_FILENO);
execlp("ls","wc","-l",NULL);
perror("error!\n");
}
}
🍉3、命名管道(fifo)-创建
💻 创建方式有两种:
1.直接通过指令创建
mkfifo myfifo
2.通过库函数实现int mkfifo(const char*pathname,mode_t mode);
#include<stdio.h>
#include<sys/stat.h>
#include<stdlib.h>
int main(){
int ret=mkfifo("myfifo_1",0644);
if(ret==-1){
perror("mkfifo error!");
exit(1);
}
return 0;
}
🌻结果展示:
🍉4、命名管道(fifo)-无血缘关系间通信
利用前面创建的命名管道myfifo和myfifo_1进行通信,fifo_w创建进程进行写,fifo_r创建进程进行读。
传输数据格式:
hello 1
hello 2
hello 3
...
💻 fifo_w.c文件:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include <fcntl.h>
int main(int argc,char* argv[]){
char buf[1024];
int fd=open(argv[1],O_WRONLY);
if(fd<0){
perror("open error!\n");
exit(1);
}
int i=1;
while(i){
sprintf(buf,"hello %d\n",i++);
write(fd,buf,strlen(buf));
sleep(1);
}
close(fd);
return 0;
}
💻 fifo_r.c文件:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char* argv[]){
char buf[1024];
int fd=open(argv[1],O_RDONLY);
if(fd<0){
perror("open error!\n");
exit(1);
}
int ret;
while(1){
ret=read(fd,buf,strlen(buf));
write(STDOUT_FILENO,buf,ret);
sleep(1);
}
close(fd);
return 0;
}
🌻结果展示:
OK,以上就是本期“linux学习篇-进程间通信方式-管道”的内容啦~~ ,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟📌~
💫如果有错误❌,欢迎批评指正呀👀~让我们一起相互进步🚀
🎉更新不易,觉得文章写得不错的小伙伴们,点赞评论关注走一波💕💕~~~谢谢啦🙏 🙏🙌