进程间通信---管道
来源:互联网 发布:剑灵女灵族捏脸数据图 编辑:程序博客网 时间:2024/06/08 01:16
1.什么是管道?
管道是一种最基本的进程通信机制,其实质是由内核管理的一个缓冲区,可以形象地认为管道的两端连接着两个需要进行通信的进程,其中一个进程进行信息输出,将数据写入管道; 另一个进程进行信息输入,从管道中读取信息。可以用下图表示
2.管道的分类
(1)匿名管道,我们平时进行操作时,曾经接触过“ls | wc -l”之类的组合。这种命名由管道符号“|”连接的两个或者多个命令组成。这里使用的管道就是匿名管道。
在程序中使用匿名管道时,需要先创建一个管道, Linux 系统中创建匿名管
道的函数为 pipe()。
int pipe(int pipefd[2]);
其参数实质是一个文件描述符。匿名管道只能在有亲缘关系的进程间使用。
匿名管道的通信过程:匿名管道利用 fork 机制
建立,刚创建出的管道,读写两端都连接在同一个进程上,当进程中调用 fork()
创建子进程后,父子进程共享文件描述符,因此子进程拥有与父进程相同的管道。pipe()创建管道后读端对应的文件描述符为 fd[0], 写端对应的文件描述符为fd[1].
fork()后的父子进程中文件描述符与管道的关系如下图
管道通过pipe()创建时自动打开,关闭应由用户实现。我们要进行父子之间通信。首先关闭父进程的读端(即close(fd[0])),关闭子进程的写端(close(fd[1]))。这样就可以父子通信,当程序结束时,匿名管道自动删除
父子通信的文件描述符与管道间的关系如下图
有亲缘关系的进程,除父子外,还有兄弟进程等具备其它联系的进程。实现这些进程间通信的实质,是关闭多个进程中多余的文件描述符,只为
待通信进程保留读端写端。
(2)命名管道端,匿名管道没有名字,只能用于有亲缘关系的进程间通信,为了打破这一局限,Linux 中设计了命名管道命名管道又名 FIFO*(first in first out),它与匿名管道
的不同之处在于: 命名管道与系统中的一个路径名关联,以文件的形式存在于文件系统中, 如此,系统中的不同进程可以通过 FIFO 的路径名访问 FIFO 文件,实现彼此间的通信。通信结束后,命名管道不销毁。
linux可以通过kfifo -m 权限 名称称 来创建命名管道。也可以通过下面的函数来创建
int mkfifo(const char* pathname,mode_t mode);
参数pathname,表示管道文件的路径,参数mode用于指定FIFO的权限。成功调用返回,否则返回-1
3.命名管道和匿名管道的特点
(1)只能进行单向通信
(2)命名和匿名管道的不同,匿名只能进行由血缘关系进程间的通信,而命名管道可以进行任何不相干进程间的通信,当然也可以进行血缘间的通信。
(3)面向流式服务。
(4)生命周期随进程。
(5)自带同步与互斥机制。
4匿名管道进行父子间通信的代码
#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>int main(){ int fd[2]; int ret=pipe(fd); //创建管道 if(ret<0) //判断是否成功 { perror("pipe"); exit(1); } pid_t pid=fork(); //创建子进程 if(pid>0) { //父进程写信息 close(fd[0]); //打开写端fd[1] char* msg="hello world"; write(fd[1],msg,strlen(msg)+1); close(fd[1]); sleep(2); } else if(pid==0) { //子进程读信息 close(fd[1]); //关闭写端 char buf[1024]={0}; ret=read(fd[0],buf,sizeof(buf)); close(fd[0]); sleep(3); write(1,buf,sizeof(buf)); } return 0;}buf,sizeof(buf)); } return 0;}
。
命名管道通信
fifo_write.c 表示向管道写数据
#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<string.h>#include<unistd.h>#include<sys/stat.h>#include<fcntl.h>int main(int argc,char* argv[]){ int ret=access("./myfifo",F_OK);//判断fifo是否存在 if(ret<0) //若fifo不存在就创建fifo { int r=mkfifo("./myfifo",0664); if(r<0) //判断文件是否创建成功 { perror("mkfifo"); exit(2); } else { printf("fifo creat succsee\n"); } } int fd=open("./myfifo",O_WRONLY); //以读的方式打开文件 while(1) //循环写入数据 { char *p="hello bit!"; write(fd,p,strlen(p)+1); sleep(2); } close(fd); return 0;}
fifo_read.c 表示从管道拿数据
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<string.h>#include<fcntl.h>int main(){ int fd=open("./myfifo",O_RDONLY); //以只读的方式打开 if(fd<0) //是否打开文件成功{ perror("open"); exit(1);} while(1) //循环读入数据{ char buf[1024]={0}; read(fd,buf,sizeof(buf)); printf("buf=%s\n",buf); sleep(2);} close(fd); return 0;}
运行结果
接收端结果
- 进程间管道通信
- 进程间通信: 管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 进程间管道通信
- 进程间管道通信
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 第八章 信号时频分析 ——8.1 信号短时傅里叶变换
- mybatis中的mapping.xml详解
- Python 高级特性之列表生成式
- 直接插入排序、希尔排序、冒泡排序、快速排序
- 递推算法求解兔子产仔问题(四)
- 进程间通信---管道
- spring bean依赖与配置
- Ubuntu 搭建 Shadowsocks服务端
- c# BlockingCollection ConcurrentQueue 内存队列的生产和消费
- Cortex-A9 的工作状态和模式
- iOS开发自我开发准则之-逻辑严谨性
- Android 实现一边圆角一边直角的Button等View
- "启动器"停止运行并死循环的解决办法
- gh0st源码分析与远控的编写(四)