目录
前言:
进程间通信的方法/IPC机制都有哪些:
- 管道
- 套接字
- 信号量
- 共享内存
- 消息队列
什么是管道?
当从一个进程连接数据流到另一个进程时,使用“管道”。通常把一个进程的输出通过管道连接到另一个进程的输入。
shell命令的连接是通过管道字符来完成,如下所示:
cmd1|cmd2
shell负责安排两个命令的标准输入和标准输出。cmd1的标准输入来自终端键盘,cmd1的标准输出传递给cmd2,作为它的标准输入。cmd2的标准输出来接到终端屏幕。管道是在内存上分配空间,cmd1把数据写到内存中,cmd2从内存中读取数据,效率高。
shell做的工作实际就是对标准输入和标准输出流进行重新连接,使数据流从键盘输入通过两个命令最终输出到屏幕上。
图示为用管道将多个进程连接起来
头文件:
#include
函数原型:
FILE *popen(const char * command,const char * open_mode);
头文件:#include
函数原型:
FILE *pclose(FILE *stream_to_close);
#include
write:
把缓冲区Buf的前nbytes个字节写入与文件描述符fildes关联的文件中。返回实际写入的字节数。
size_t write(int fildes,const void *buf,size_t nbytes)
read:
从文件描述符filedes相关联的文件里读入nbytes个字节的数据,并且把他们放到数据区buf中。返回实际读入的字节数。
size_t read(int dildes,void* buf,size_t nbytes);
open:
创建一个新的文件描述符
- #include
- #include
- #include
-
- int open(const char * path,int oflags);
- int open(const char *path,int oflags,mode_t mode);
管道也是个文件,用文件操作的命令对管道进程操作。管道存放在内存中,读取速度很快。
- 只能进行父子间通信
- 使用pipe创建无名管道
- pipe:
- 头文件:
#include int pipe(int file_descriptor[2]);- 成功返回0,失败返回-1
- file_descriptor[0]:管道读端的描述符
- file_descriptor[1]:管道写端的描述符
两个返回的文件描述符以一种特殊的方式连接起来。写到file_deacriptor[1]的所有数据都有可以从file_descriptor[0]读回来。数据基于先进先出的原则(通常写为FIFO)进行处理,这意味着如果把字节1,2,3写到file_deacriptor[1],从file_deacriptor[0]读取到的数据也会是1,2,3,这也栈的处理方式不同,栈采用后进先出,写作LIFO。
- 函数在两个程序之间传递数据不需要启动一个shell来解释所请求的命令,他同时还提供了对读写数据的更多控制。
- pipe函数的参数是一个由两个整数类型的文件描述符组成数组的指针。该函数在数组中天上两个新的文件描述符后返回0,如果失败则返回-1并设置error来表示失败的原因。
- 代码演示:父进程写入数据,子进程读取:
#include #include #include #include #include int main() { int fd[2];//写端描述符 assert(pipe(fd)!=-1); pid_t pid=fork();//open->fork,父子共享文件描述法 assert(pid!=-1); if(pid==0)//子进程 { close(fd[1]); char buff[128]={0}; read(fd[0],buff,127); printf(fd[0]); } else { close(fd[0]); write(fd[1],"hello",5); close(fd[1]); } exit(0); }- 代码牵扯到一个知识点:先open打开文件再fork出子进程,此时,父子进程共享文件偏移量/文件描述符。注意:这里使用的文件描述符而不是文件流,所以我们必须用底层的read和write调用来访问数据,而不是用文件流库函数fread和fwrite。
fork,可以把fds[0][1]带给子进程,传递描述符
子进程可以共享,管道就通过fork把管道描述符带给fork
- 有名管道实现任意进程间通信
- 有名管道的创建:
- 创建命令:mkfifo
- 打开管道:open();
- 读数据:read();
- 写入数据:write();
- 关闭管道:close()
- 代码实现有名管道间通信:
a.c:读取fifi的管道文件,写入5个字符的"hello"数据进去。
#include #include #include #include #include #include int main() { int fd=open("fifi",O_WRONLY); assert(fd!=-1); printf("fd=%d\n",fd); write(fd,"hello",5); close(fd); }b.c
#include #include #include #include #include #include int main() { int fd=open("./fifi",O_RDONLY); assert(fd!=-1); printf("fd=%d\n",fd); char buff[128]={0}; read(fd,buff,127);//不读\0 printf("read %s\n",buff); close(fd); }
open打开管道后,会开辟如下所示大小的空间:
头指针:当前待写入的数据位置
尾指针:当前待读取数据的位置,图示为即将读取h
abcdefg为已经读取的数据,用户使用过的空间可以被重新利用,当前空间满了可以写入在缓冲区指针位置。--相当于循环队列
IPC机制有:IPC进程间通信。