Linux-进程通信(管道)
2018-03-28 16:04
288 查看
进程间通信目的
数据传输:一个进程需要将他的数据传输给其他进程。资源共享:多个进程之间共享相同的资源。
通知事件:一个进程需要向另一个进程发送消息,通知它发生了某种事件。
进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
管道
管道是unix中最古老的进程间通信的方式。管道的定义:我们把从一个进程连接到另一个进程的一个数据流称为“管道”
如图所示,注意的是数据的”传输”都是在内核中进行。
管道分为两种:匿名管道与命名管道。
匿名管道
函数原型:参数:文件描述符数组,
fd[0]:表示读端
fd[1]:表示写端
返回值:成功返回0,失败返回-1与错误代码。
举例说明;
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> int main() { int fd[2]; char buf[100]; int len; int ret=pipe(fd); if(ret==-1) { perror("pipe"); exit(0); } //read from stdin while(1) { fgets(buf,100,stdin); len=strlen(buf); //write into pipe ssize_t s=write(fd[1],buf,len); if(s!=len) { perror("write"); break; } memset(buf,0,sizeof(buf)); //read from pipe len=read(fd[0],buf,100); if(len==-1) { perror("read"); break; } //write to stdout s=write(1,buf,len); if(s!=len) { perror("write"); break; } } }
该例实现了,从键盘(标准输入)中获取数据,写入到管道里,再从管道里读出,写入标准输出中(显示屏)。
结果如下:
原理可以用下图来解释:
fork之后的父子进程各自都有一个读端和写端。
将父进程的写端关掉,子进程的读端关掉。
也可以从文件描述符的角度来说明:
父进程有一个files_struct结构体,里有一组文件指针数组。
父进程fork出子进程后,子进程也有一套同样的内容。
最后一步,父进程关闭读端,子进程关闭写端。
可以注意到,不管从哪个角度来理解管道这种机制,都是从父进程fork子进程开始的,所以将这种管道称为“匿名管道”,具有亲缘关系的。
匿名管道特点
只能用于具有共同祖先的进程(具有亲缘关系的,兄弟进程也可以)之间通信。一般而言,进程退出,管道释放。所以管道生命周期随进程。
一般而言,内核会对管道进行同步与互斥。
管道提供面向字节流服务,数据只能向一个方向传输,双方传输时,需要建起两个管道。
管道读写规则
写方一只写,读方不读:write调用阻塞,直到有进程读走数据。写方不写,读方一直读:read调用阻塞,直到有数据来为止。
写方将写端关闭,读方一直读:读方将读完然后返回0;
写方一直写,读方将读端关闭:会产生SIGPIPE信号,终止write进程。
命名管道
匿名管道的一个限制就是必须在具有共同祖先的进程间通信。如果想在毫无相关的进程间交换数据,就要使用命名管道。
命名管道是一种特殊类型的文件。
创建一个命名管道有两种方式:
在命令行创建:
mkfifo filename
命名管道可以从程序里创建,相关函数是;
int mkfifo(const char8 filename,mode_t mode);
成功返回0,失败返回-1;
举例说明:
server.c: #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main() { if(mkfifo("./fifo",0644)<0) { printf("mkfifo error!\n"); return 1; } int fd=open("./fifo",O_RDONLY); if(fd<0) { perror("open"); return 2; } char buf[64]; while(1) { ssize_t s=read(fd,buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("server#%s\n",buf); } else { printf("client quit\n"); break; } } close(fd); return 0; } client.c: #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int fd=open("./fifo",O_WRONLY); if(fd<0) { perror("open"); return 2; } char buf[64]; while(1) { printf("please enter:"); scanf("%s",buf); if(strcmp(buf,"quit")==0) { break; } write(fd,buf,strlen(buf)); } close(fd); return 0; }
实现效果如下:
匿名管道与命名管道的区别
匿名管道有函数pipe创建并打开命名函数有mkfifo创建,打开用open
命名管道与匿名管道之间唯一的区别在他们创建于打开的方式不同,一旦这些工作做好之后,他们具有相同的的语义。
最大的区别是:命名管道时文件在硬盘上有对应的文件,而匿名管道是在内核中实现的。
打开规则
为读打开时:无写方:阻塞直到有相应进程来打开该FIFO
有写方:返回成功;
为写打开:
无读方:阻塞直到有相应进程为读而打开该FIFO
有读方:返回失败;
相关文章推荐
- Linux进程通信(一)——pipe管道
- Linux 进程通信(无名管道)
- Linux进程通信(1):管道(上)
- Linux 进程通信(System V) 第一节 ------> 管道 pipe
- Linux 进程通信学习1-管道
- Linux中的进程通信(一)--命名管道
- Linux 进程通信(System V)管道
- 【Linux探索之旅】第三部分第二课:流、管道、重定向,三管齐下
- Linux运维学习笔记之三:组合命令及命令分类、符号、管道 、工具集
- linux 无名管道pipe和有名管道FIFO
- linux 8 -- 管道组合Shell命令进行系统管理
- linux学习(2)--环境变量和管道
- 进程间通信管道进阶篇:linux下dup/dup2函数的用法
- Linux中IPC机制:管道和FIFO
- Linux 管道的I/O
- Linux进程间通信——使用命名管道
- 【linux高级程序设计】(第九章)进程间通信-管道 1
- linux 有名管道(FIFO)
- Linux 上实现双向进程间通信管道
- Linux进程通信:管道