现在linux使用的IPC(Inter-Process Communication,进程间通信)方式有以下几种:
-(1)管道(pipe)和匿名管道(FIFO)
-(2)信号(signal)
-(3)消息队列
-(4)共享内存
-(5)信号量
-(6)套接字(socket)
网站建设哪家好,找成都创新互联公司!专注于网页设计、网站建设、微信开发、成都微信小程序、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了那曲免费建站欢迎大家使用!
什么是管道
管道是Unix中最古老的进程间通信的形式。我们把一个进程连接到另一个进程的一个数据流成为一个“管道”。
- 管道是半双工的,数据只能向一个方向流动;需要双方通信的时候,需要建立其两个管道。
只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)进行通信。
pipe函数
#include
int pipe(int pipefd[2]); 功能:创建无名管道
参数:文件描述符组。fd[0]表示读端,fd[1]表示写端。
返回值:成功返回0,失败返回错误代码
也就是说,在fork()之前pipe(),就可以使得父子进程之间建立起一个管道,画个图:
父子进程都会打开5个文件描述符,除了默认的0、1、2。还有fd[0]、fd[1]。测试一下,就会知道这两个文件描述符为3、4。
写串代码用一用:#include
#include #include #include int main() { int fd[2]; int retByte; pid_t pid; char buf[20] = ""; pipe(fd); /*创建无名管道*/ //printf("%d,%d\n",fd[0],fd[1]); pid = fork(); if(pid == -1) { perror("create fork"); return -1; } if(pid == 0) { //子进程,写端,使用fd[1] //close(fd[0]); //close(fd[1]); while(1) { scanf("%s",buf); if( write(fd[1],buf,strlen(buf)) == -1) { perror("write"); return -1; } memset(buf,0,20); if(read(fd[0],buf,5) > 0 ) { printf("child-read msg: %s\n",buf); } } } else { //父进程,读端,使用fd[0] while(1) { memset(buf,0,20); retByte = read(fd[0],buf,5);//每次只读5个 if( retByte == -1) { perror("read"); return -1; } if(retByte > 0) { printf("parent-read msg: %s\n",buf); } } } return 0; } 运行结果:
那么,如果没有读端呢?也就是父子进程的fd[0]都关闭了,会有什么现象呢?void handler(int no) { printf("SIGPIPE.\n"); } int main() { int fd[2]; int retByte; int rlt; pid_t pid; char buf[20] = ""; rlt = pipe(fd); /*创建无名管道*/ //printf("%d,%d\n",fd[0],fd[1]); signal(SIGPIPE,handler); if(rlt != 0) { perror("pipe"); return -1; } pid = fork(); if(pid == -1) { perror("create fork"); return -1; } if(pid == 0) { //子进程,写端,使用fd[1] close(fd[0]); //close(fd[1]); while(1) { scanf("%s",buf); if( write(fd[1],buf,strlen(buf)) == -1) { perror("write"); return -1; } memset(buf,0,20); } } else { //父进程,读端,使用fd[0] close(fd[0]); while(1) { } } return 0; }
运行结果:
会出现管道破裂!!(如果没有重写管道破裂的处理函数,系统默认的处理方式就是杀死进程,父子进程都over了)管道读写规则
所以,总结一下读写规则:
读规则:
1)缓冲区没数据:阻塞
2)缓冲区的数据少于请求字节数:缓冲区有多少就读多少
3)缓冲区的数据多于请求字节数:只读取请求字节数,剩下的还在缓冲区
4)写端关闭:读端等待。
写规则:
1)缓冲区满了:写不进去
2)没有读端:管道破裂,父子进程都结束了。调试到write,发生SIGPIPE。
注意:读端和写端的对应关系可以是一对一、一对多、多对一、多对多的。练习
上面讲到,缓冲区如果满了,就写不进去了。那么缓冲区有多大呢?换言之,如何检测linux中管道的容量?
代码如下:int main() { int fd[2]; pipe(fd); char buf[4096]; //4k int i,loop,ret; for(i = 0 ; i < sizeof(buf) ; i++) { buf[i] = 'a'; } loop = 100 ; //如果循环结束,还没阻塞,增加循环次数 for(i = 0; i < loop ; i++) { ret = write(fd[1],buf,sizeof(buf)); if(ret == -1) { perror("write error!\n"); return 1; } else { printf("write successfully! "); printf("size: %d K\n", (i+1)*4); } } close(fd[0]); close(fd[1]); return 0; }
运行结果:
在写完64k的时候出现阻塞,说明管道已经满了。
分享文章:IPC之管道
URL分享:http://scgulin.cn/article/goosds.html