Linux--进程间通信--管道
来源:互联网 发布:小米6陶瓷尊享版 知乎 编辑:程序博客网 时间:2024/05/20 15:37
Linux:进程间通信--命名管道:命名管道
1进程间通信
进程间通信,英文又称IPC(InterProcess Communication),因为每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户地址空间烤到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制就称为进程间通信。
2管道
2.1概念
管道是一种最基本的IPC机制,从本质上讲,管道也是一种文件。在LInux系统中,我们经常通过符号"|"来使用管道,用以连接两个多个命令。实际上,管道是进程与进程间的数据流通管道,它是的数据可以以一种“流”的形式在进程间流动。
管道的特点:
- 单向通信。
- 依赖文件系统。管道的生存周期随进程的退出,管道就被销毁(随进程)。
- 管道只能用于血缘关系的进程,通常用于父子进程。
- 管道在进行读写操作时,以数据流方式。
- 同步访问。
2.2管道的创建
Linux系统下,管道是通过pipe函数创建的,函数原型如下:
#include<inistd.h>int pipe(int fileds[2]);//成功返回0,失败返回-1其中,参数fileds[2]是一个长度为2的文件描述符数组,fileds[0]是读端,fileds[1]是写端。
2.3管道的读写
在单个进程中创建管道几乎没有意义的,因为管道存在的意义就是进行进程之间的通信。上面我们介绍了管道的特点,其中一条是,管道只能用于有血缘关系的进程,所以我们通过父子进程之间的通信演示一下管道的使用。
说明:
父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端,父进程调用fork创建了子进程,子进程也有两个文件描述符指向同一管道。
因为管道是单向通信的,所以父进程关闭写端,子进程关闭读端。子进程可以往管道里写,父进程可以在管道里读,数据从写端流入,从写端流出,实现进程通信。
代码:
#include<stdio.h>#include<unistd.h>#include<errno.h>#include<string.h>//创建管道,子进程只写,父进程只读int main(){int fds[2];int ret=pipe(fds);if(ret==-1){printf("Create pipe error! errno code is:%d\n",errno);return 1;}pid_t id=fork();if(id<0){printf("fork error!");return 2;}else if(id==0){//childclose(fds[0]);//关闭读char* msg="I am child!";while(1){write(fds[1],msg,strlen(msg)+1);sleep(1);}}else{close(fds[1]);//关闭写char buf[1024];while(1){read(fds[0],buf,sizeof(buf));printf("father read :%s\n",buf);}}return 0;}
从图中可以验证管道的单向通信,如果想实现父进程给子进程法消息,我们该怎么办?
我们可以再新建一个管道,使父进程写,子进程读,就完美解决了这个问题。
但是使用管道还有四种特殊情况要注意(以父进程读,子进程写为例):
1.如果子进程的写端的文件描述符关闭了,此时管道还有数据,此时父进程在读取完管道剩余数据后,在此read会阻塞返回0,就像读到文件尾。
#include<stdio.h>#include<stdio.h>#include<unistd.h>#include<errno.h>#include<string.h>//创建管道,子进程只写,父进程只读int main(){int fds[2];int ret=pipe(fds);if(ret==-1){printf("create pipe errro!\n");return 1;}pid_t id=fork();if(id<0){printf("fork error!\n");return 2;}else if(id==0){//childclose (fds[0]);//关闭读int i=0;char* msg="I am child!";while(i<5){write(fds[1],msg,strlen(msg)+1);sleep(1);++i;}close(fds[1]);//写入5次,关闭写}else{//fatherclose(fds[1]);//关闭写char buf[1024];int j=0;while(j<100){memset(buf,'\0',sizeof(buf));int ret=read(fds[0],buf,sizeof(buf));printf("%s; code is:%d\n",buf,ret);++j;}if(waitpid(id,NULL,0)<0)return 3;}return 0;}
2.如果子进程的写端没有关闭,但是也没有向管道写数据,此时父进程读取完管道的剩余数据,再次read会阻塞,直到管道中有数据读才返回。
#include<stdio.h>#include<stdio.h>#include<unistd.h>#include<errno.h>#include<sys/wait.h>#include<string.h>//创建管道,子进程只写,父进程只读int main(){int fds[2];int ret=pipe(fds);if(ret==-1){printf("create pipe errro!\n");return 1;}pid_t id=fork();if(id<0){printf("fork error!\n");return 2;}else if(id==0){//childclose (fds[0]);//关闭读int i=0;char* msg="I am child!";while(1){if(i<3){write(fds[1],msg,strlen(msg)+1);}sleep(1);}//close(fds[1]);//写入5次,关闭写}else{//fatherclose(fds[1]);//关闭写char buf[1024];int j=0;while(j<20){memset(buf,'\0',sizeof(buf));int ret=read(fds[0],buf,sizeof(buf));printf("%s; code is:%d\n",buf,ret);++j;}if(waitpid(id,NULL,0)<0)return 3;}return 0;}
3.如果父进程的读端关闭了,这时子进程向管道写,那么进程会收到SIGPIPE,通常会导致程序异常终止。
#include<stdio.h>#include<stdio.h>#include<unistd.h>#include<errno.h>#include<sys/wait.h>#include<string.h>//创建管道,子进程只写,父进程只读int main(){int fds[2];int ret=pipe(fds);if(ret==-1){printf("create pipe errro!\n");return 1;}pid_t id=fork();if(id<0){printf("fork error!\n");return 2;}else if(id==0){//childclose (fds[0]);//关闭读int i=0;char* msg="I am child!";while(1){if(i<10){write(fds[1],msg,strlen(msg)+1);}sleep(1);++i;}//close(fds[1]);//写入5次,关闭写}else{//fatherclose(fds[1]);//关闭写char buf[1024];int j=0;while(j<5){memset(buf,'\0',sizeof(buf));int ret=read(fds[0],buf,sizeof(buf));printf("%s; code is:%d\n",buf,ret);++j;}close(fds[0]);sleep(10);//睡眠10秒,终止if(waitpid(id,NULL,0)<0)return 3;}return 0;}
4.父进程的读端口没关闭,但是父进程也没有从管道里读文件,当子进程向管道写数据时,管道被写满时,再次write会阻塞,直到管道有空位置才写入数据并返回。
#include<stdio.h>#include<stdio.h>#include<unistd.h>#include<errno.h>#include<sys/wait.h>#include<string.h>//创建管道,子进程只写,父进程只读int main(){int fds[2];int ret=pipe(fds);if(ret==-1){printf("create pipe errro!\n");return 1;}pid_t id=fork();if(id<0){printf("fork error!\n");return 2;}else if(id==0){//childclose (fds[0]);//关闭读int i=0;char* msg="I am child!";while(1){write(fds[1],msg,strlen(msg)+1);printf("%s; code is:%d\n",msg,i);//sleep(1);++i;}}else{//fatherclose(fds[1]);//关闭写}return 0;}
0 0
- Linux 进程间通信管道
- Linux 进程间通信 管道
- Linux进程间通信:管道
- Linux进程间通信-管道
- Linux进程间通信 -- 管道
- Linux--进程间通信--管道
- linux进程间通信--管道
- Linux间进程通信 管道
- Linux进程间通信之管道通信
- Linux进程间通信之管道通信
- Linux 进程间通信--- 管道通信
- linux进程间通信-管道通信
- Linux下进程间通信--管道通信
- Linux进程间的通信--管道通信
- Linux进程通信:管道
- Linux进程通信-管道
- linux 进程通信 ----管道
- linux进程通信--管道
- vi编辑器简单配置
- android调用系统浏览器和拨打电话
- 使用 Log4j 将日志记录到远程系统
- gulp安装&less插件
- Web9. CSS常见属性2
- Linux--进程间通信--管道
- 【机器学习】【可视化】Matplotlib的scatter函数用法
- 2.spark的RDD特性(Resillient Distributed Dataset)
- C3P0数据库连接池的基本使用
- android移除数据
- (回溯法)LeetCode#79. Word Search
- Java中调用Oracle存储过程及存储函数
- photoshop 快捷键操作 and 基本操作
- TensorFlow+MNIST实例讲解