IPC基本概念
进程间通信:InterProcess Communication
进程间通信常用的4种方式
a. 管道 - 简单
b. 信号 - 系统开销小
c. 共享映射区 - (有无血缘关系的进程间通信都可以)
d.本地套接字 - 稳定
e.消息队列
管道的概念
本质
1、内核缓冲区
2、伪文件 - 不占用磁盘空间
特点
1、读端,写端,对应两个文件描述符
数据写端流入, 读端流出
2、操作管道的进程被销毁之后,管道自动被释放
3、 管道默认是阻塞的
管道的原理
1、内部实现方式:队列
环形队列
特点:先进先出
2、缓冲区大小:
默认4k
大小会根据实际情况做适当调整
管道的局限性
1、队列
数据只能读取一次,不能重复读取
2、 匿名管道
适用于有血缘关系的进程
管道的读写行为
1、 读操作
有数据
read - 正常读,返回读出的字节数。
无数据
写端全部关闭
read解除阻塞,返回0
相当于读文件读到了尾部
没有全部关闭
read阻塞
2、写操作
读端全部关闭
管道破裂,进程被终止
内核给当前进程发信号SIGPIPE
读端没全部关闭
缓冲区写满了
write 阻塞
缓冲区没有满
write继续写
设置非阻塞
1、默认读写两端都阻塞
2、设置读端为非阻塞pipe(fd)
a、fcntl - 变参函数
修改文件属性 - open的时候对应flag属性
b、设置方法
获取原来的flags
int flags = fcntl(fd[0], F_GETFL);
设置新的flags
flag |= O_NONBLOCK;
创建匿名管道
int pipe(int fd[2]);
fd- 传出参数
fd[0] - 读端
fd[1] - 写端
父子进程使用管道通信
1、父进程读
– 关闭写端
2、子进程写
– 关闭读端
测试源码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, const char* argv[])
{
int fd[2];
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe error");
exit(1);
}
printf("fd[0] = %d\n", fd[0]);
printf("fd[1] = %d\n", fd[1]);
pid_t pid = fork();
if(pid == -1)
{
perror("fork error");
exit(1);
}
// 父进程 写 , 关闭读操作
if(pid > 0)
{
sleep(1);
close(fd[0]);
char* p = "hello, world\n";
write(fd[1], p, strlen(p)+1);
close(fd[1]);
wait(NULL);
}
else if(pid == 0)
{
close(fd[1]);
char buf[1024];
read(fd[0], buf, sizeof(buf));
printf("buf = %s\n", buf);
close(fd[0]);
}
return 0