进程间通讯—管道
来源:互联网 发布:php跳转代码 编辑:程序博客网 时间:2024/05/16 19:15
进程间通讯:
每个进程都有自己的用户地址空间,一个进程的全局变量在另一个进程中是看不到的,如果两个进程想要交换信息,就需要通过内核,在内核中开辟一块缓存区,把进程1里的数据拷到内核,进程2从内核读走。内核提供的这种机制就是进程间通讯。
本质:让不同的进程访问同一块系统资源。
1、进程间通讯机制——管道
从本质上来说,管道也是文件,但它与一般的文件不相同,它克服了使用文件通讯的缺点:
(1):管道文件只占据inode,只是传输数据,不在磁盘上占据空间。
(2):管道在内存上也是一个固定大小的缓存区,该缓冲区的大小为1页,即4k字节。文件就不会限制大小,除非磁盘已满。但在写管道时,管道写满,当这种情况发生,随后再对管道的write()调用将被阻塞,等待数据被读取,留出空间再write()。
从管道中读文件是一次性操作,数据一旦被读取,它就从管道中消失,释放空间。
2、管道操作:
有名管道:应用于任意两个进程数据的单向传递
创建:命令方式:mkfifo 函数方式:mkfifo();
打开: int open(const char *pathname,int flag);
写数据: int write(int fd,char* buff,int size);
读数据:int read(int fd,char *buff,size);
关闭:int close(int fd);
代码实现:
功能: 我们需要运行两个不同的程序,实现两个进程之间的数据传递。
1、利用命令 创建管道文件
2、在 a.c 里实现用户循环输入字符串,并写进管道;在 b.c 里实现读取用户输入的字符串
(1) a.c 文件向管道里写:
#include<stdio.h>#include<unistd.h>#include<string.h>#include<fcntl.h>int main(){ int fd=open("FIFO",O_WRONLY);if(fd==-1){ exit(0);}char buff[128]={0};printf("please input:\n");fgets(buff,128,stdin);while(strncmp(buff,"end",3)!=0){ write(fd,buff,strlen(buff)-1);memset(buff,0,128);fgets(buff,128,stdin);}close(fd);}
(2)b.c文件从管道里读:
#include<stdio.h>#include<fcntl.h>#include<string.h>#include<unistd.h>#include<stdlib.h>int main(){ int fd=open("FIFO",O_RDONLY);if(fd==-1){ exit(0);}char buff[128]={0};while(read(fd,buff,127)>0){ printf("%s\n",buff);}close(fd);}
测试运行结果:
3、最重要的点来了:有名管道的特点就是阻塞运行
阻塞运行函数:函数调用以后并不会立即返回,需要等待某些条件的发生才能返回。
(1):如果一个进程以只写方式打开一个管道文件,那么open函数会阻塞运行,直到有一个进行以只读方式打开管道文件,open才会返回,进程才会接着进行。
(2):如果一个进程以只读方式打开一个管道文件,那么open函数会阻塞运行,直到有一个进程以只写方式打开管道文件,open才会返回,进程才会接着进行。
你运行上面的代码就会知道,两个文件必须同时打开才能运行。
(3):read 函数也会阻塞运行,直到写端写入数据,或者所有的写端都关闭。
(4):read读取数据,并将内存上的已读数据清空。
如果你让写文件 sleep(10);先执行读,那么能读出来吗?
等10s 后,写进去了,才能读出来,那么是谁阻塞?就是read函数啦!
(5):write函数也会阻塞运行,因为管道是在内存中的一小块,当这一小块存满以后,再进行写的时候只能等待,等一部分数据被读走以后,再接着写。
4、无名管道:
相对于有名管道,无名管道是使用时产生,不使用时释放,在系统上不会留下一丝痕迹。
那么来无影去无踪的,连名字也不知道,它该如何找到呢?
我们通过父子进程实现。为什么要用父子进程实现?
父进程创建子进程,子进程和父进程指向同一块区域,那么我们就可以利用来通讯。而且父进程结束,子进程也就结束了。那么依赖父子进程的特性就可以同时占用一个管道,进行通讯了。
一个管道由一个进程创建,然后该进程调用fork。父子进程就可以应用该管道。
管道的创建 :int pipe(int fd[2]);
打开: fd[0] 读 fd[1] 写
读: read(fd[0],buff,size);
写: write(fd[1],buff,len);
关闭:close(fd[0]);
close(fd[1]);
那么如何实现通讯呢?
fork产生后:4个读写,但管道属于半双工通讯,只有一个读,一个写。 父读子写或者父写子读。
代码实现:fifo 文件
实现功能为:父进程进行写,从用户端循环输入字符,写进管道里,子进程从管道里进行读,并输出字符串和长度。
#include<unistd.h>#include<stdio.h>#include<fcntl.h>#include<string.h>int main(){ int fd[2];pid_t pid;char buff[128];char buff1[128];if(pipe(fd)<0){ printf("pipe error\n");}pid=fork();if(pid<0){ printf("fork error\n");}else if(pid>0){ close(fd[0]);printf("plesae input\n");fgets(buff,128,stdin);while(strncmp(buff,"end",3)){ write(fd[1],buff,strlen(buff)-1);memset(buff,0,128);fgets(buff,128,stdin);}}else{ close(fd[1]); while(read(fd[0],buff1,127)>0){ printf("%s\n",buff1); printf("num=%d\n",strlen(buff1));printf("please input\n");}}}
运行结果:
- 进程间通讯—管道
- 进程间通讯--管道
- 进程间通讯:管道
- 进程间通讯--管道
- 进程间通讯——有名管道
- 进程间通讯-——管道
- 进程间通讯——无名管道
- 进程间通讯——管道(有名管道)
- Linux进程间通讯--管道(有名管道
- 管道实现进程间通讯
- 管道实现进程间通讯
- 管道实现进程间通讯
- 进程间通讯---匿名管道
- linux进程间通讯--管道
- Linux-进程间通讯-管道
- 进程间通讯-有名管道
- 进程间通讯-无名管道
- delphi 进程间通讯(管道通讯)
- tablayout简单使用
- 八进制数和十六进制数的表示
- 网络请求
- VLC图传系统搭建
- 【数据实时分析】流计算使用教程
- 进程间通讯—管道
- angular的弹出框
- 移动大脑-SpringMVc搭建RestFul后台服务(六)-微信支付(Android)
- 超级工程(2)想到的
- tomcat分割日志以及与logback的区别和注意事项
- 横向滚动
- Linux内核数据结构kfifo详解
- DrawerLayout侧滑栏简单使用
- jquery 的收集整理和记录--jquery查找元素