Linux进程间通信(上)
目录
什么是管道
匿名管道
匿名管道接口
使用匿名管道通信
匿名管道特性
fcntl函数
函数接口
设置非阻塞属性
命名管道
创建命名管道
命名管道特性
代码验证
什么是管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
匿名管道
匿名管道接口
pipe函数可以用来创建匿名管道,从而实现进程间通信,函数如下:
先来理解一下pipe()函数的参数到底是什么意思,调用完pipe函数后将参数打印出来:
输出了"3,4",这是两个小正数,这很容易让我们想到了文件描述符,那么到底是不是呢?我们使用指令进入以该进程号命名的文件夹中:
显然,这两个参数正是文件描述符,那么这两个文件描述符与匿名管道的关系呢?请看下图来理解:
知道了这层关系之后,就可以来用一用这个缓冲区了,如下代码:
代码完成的功能只是在同一个进程中使用管道,没有体现进程间通信,那么想要用匿名管道完成进程间通信,需要怎么做呢?
使用匿名管道通信
通过以上图解分析,要让不同的进程使用匿名管道进行通信,那么这些进程必须拥有匿名管道读写两端的文件描述符,也就是说这些进程有亲缘关系,比如父子进程,满足下图对应的关系:
如下代码中,父进程往管道中写,子进程从管道中读:
1 #include <stdio.h>2 #include <unistd.h>3 #include <string.h>4 int main(){5 int fd[2];6 pipe(fd);//创建匿名管道7 pid_t ret=fork();8 if(ret<0){9 return 0;10 }else if(ret==0){11 char arr[10]={0}; 12 read(fd[0],arr,sizeof(arr)-1);//从匿名管道中读13 printf("%s\n",arr);14 while(1){15 }16 }else{17 const char* str="Hello";18 write(fd[1],str,strlen(str));//往匿名管道中写19 while(1){20 }21 }22 return 0;23 }
代码执行后:
成功打印了"Hello",说明子进程读到了管道中的内容,进程间通信成功了,这时我们再来查看父子进程是否都拥有文件描述符呢?如下:
此时,父子进程同时拥有匿名管道两端的文件描述符,进程通信成功。
匿名管道特性
1.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。
2.只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
3.一般而言,进程退出,管道释放,所以管道的生命周期随进程。
4.管道大小是64KB,如下代码中一直往管道中写,一次写一个字节,直到将管道写满,可以看到最终打印的数字是65536,也就是65536个字节,等于64KB。
5.管道提供字节流服务,也就是说从读端进行读的时候,是将管道中的内容读走了,且读端可以自定义读多少内容。
6.当读写小于pipe_size时,管道保证原子性。pipe_size是4096字节,通过命令:"ulimit -a"可以查看,原子性的意思就是说:一个操作要么不间断的全部被执行,要么一个也没有执行,不存在中间状态。如下:
7.调用pipe创建出来的读写两端的文件描述符,默认都是阻塞属性。就是说:调用write一直写,读端不去读,写满之后write会阻塞。调用read一直读,管道内部被读完后,read会阻塞。如下代码来验证写阻塞,读阻塞与之相类似。使用命令:"pstack [pid]"可以查看进程当前正在干什么。
fcntl函数
函数接口
fcntl函数可以用来设置管道为非阻塞属性,该函数如下:
来测试下这个函数,用来获取管道读写两端的:
此时输出的0和1就分别代表读写两端文件描述符的属性信息不同。
设置非阻塞属性
1.写不关闭,读设置为非阻塞属性。让子进程来读,看看会发生什么现象,代码如下:
1 #include <stdio.h> 2 #include <unistd.h>3 #include <fcntl.h> 4 int main(){ 5 int fd[2];6 int ret=pipe(fd);7 if(ret<0){8 perror("pipe");9 return 0;10 }11 pid_t pid=fork();12 if(pid<0){13 perror("fork");14 return 0;15 }else if(pid==0){16 close(fd[1]);17 int flag=fcntl(fd[0],F_GETFL);18 fcntl(fd[0],F_SETFL,flag|O_NONBLOCK);19 char str[1000]={0};20 ssize_t size_read=read(fd[0],str,sizeof(str)-1);21 printf("%ld\n",size_read);22 perror("read");23 }else{24 close(fd[0]);25 while(1){}26 } 27 return 0;28 }
运行后:
此时read的返回值为-1,而errno被设置为EAGAIN,读失败。
2. 写关闭,读设置为非阻塞属性。让子进程来读,上述代码中父进程关闭写端就可以了,直接来看运行结果:
read的返回值为0,读成功了,读到了0个字节。
3.读不关闭,写设置为非阻塞。让子进程来写,观察当把管道写满后的现象,代码如下:
1 #include <stdio.h> 2 #include <unistd.h>3 #include <fcntl.h>4 int main(){5 int fd[2];6 int ret=pipe(fd);7 if(ret<0){8 perror("pipe");9 return 0;10 }11 pid_t pid=fork();12 if(pid<0){13 perror("fork");14 return 0;15 }else if(pid==0){16 close(fd[0]);17 int flag=fcntl(fd[1],F_GETFL);18 fcntl(fd[1],F_SETFL,flag|O_NONBLOCK);19 while(1){20 ssize_t size_write=write(fd[1],"s",1);21 printf("%ld\n",size_write);22 perror("write");23 }24 }else{25 close(fd[1]);26 while(1){}27 }28 return 0;29 }
运行代码后:
此时write返回-1,告诉我们资源不可用,写失败。
4.读关闭,写设置为非阻塞。让子进程来写,在上述代码父进程中将读写都关闭即可,运行结果如下:
好像什么都没有发生?我们使用命令来查看当前进程的状态:
子进程中有死循环,父进程没有退出,子进程不会自动退出的,但是此时的现象表明子进程退出了,为什么呢?
本质原因是没有进程在从管道中读了,写入的内容永远不会被读出来,此时继续写入,管道就会破碎,写端进程就会收到一个SIGPIPE信号,导致写端进程崩溃。
命名管道
创建命名管道
1.mkfifo命令创建
2.mkfifo函数创建
下面来用这个函数创建一个命名管道:
命名管道特性
支持不同的进程进行进程间通信,不依赖亲缘性了。
代码验证
拥有了命名管道后,就可以让不同的进程进行进程间通信,如下代码中,命名管道文件存在于当前代码所在目录的上级目录,用open函数打开后,通过各自的文件描述符就可以进行进程间通信了。
观察现象,成功进行了进程间通信。
Linux进程间通信(上)相关推荐
- linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)
linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...
- linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)
linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...
- linux进程间通信:POSIX 消息队列 ----异步通信
在上一篇中linux进程间通信:POSIX 消息队列我们知道消息队列中在消息个数达到了队列所能承载的上限,就会发生消息的写阻塞. 阻塞式的通信影响系统效率,进程之间在通信收到阻塞时并不能去做其他事情, ...
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...
- Linux进程间通信(二):信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()...
我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我 ...
- 20155301 滕树晨linux基础——linux进程间通信(IPC)机制总结
20155301 滕树晨linux基础--linux进程间通信(IPC)机制总结 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在 ...
- Linux 进程间通信
引言 进程通信的目的: 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一 ...
- Linux进程间通信中的文件和文件锁
Linux进程间通信中的文件和文件锁 来源:穷佐罗的Linux书 前言 使用文件进行进程间通信应该是最先学会的一种IPC方式.任何编程语言中,文件IO都是很重要的知识,所以使用文件进行进程间通信就成了 ...
- linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)
linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...
- linux 进程间通信 dbus-glib【实例】详解二(下) 消息和消息总线(ListActivatableNames和服务器的自动启动)(附代码)
linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...
最新文章
- mac android 真机调试
- bootstrap基础学习四篇
- 8-Trusted Board Boot
- 编码时的一些普适原则
- DDD 领域驱动设计:贫血模型、充血模型的深入解读
- 基于FPGrowth挖掘算法的乳腺癌中医症型关联规则挖掘
- 看printk引发的一点思考
- Docker Desktop 向大公司宣告收费,网友大呼:是时候弃用了!
- 排序算法(3)----归并排序
- sql查看数据库线程数_SQL Server始终在可用性组数据库上的最大辅助线程
- 纳税人基本信息与服务器端基本信息不符,网上报税对浏览器有什么要求吗
- java后台与ISO端app对接
- python 写txt 换行_写入txt文本的内容为什么没换行效果?
- 系列(一):加解密字符串及配置文件(CSASPNETEncryptAndDecryptConfiguration)
- Linux学习—编译
- idea破解到2100年
- 门限电子签名DEMO(协同签名)
- Dell服务器做磁盘阵列
- Android 图片波浪动画,Android水纹波浪动画
- opera中添加搜索引擎