文章目录
1.IPC
Inter Process Communication
进程间通信常用的几种方式
1.管道通信:有名管道,无名管道
2.信号- 系统开销小
3.消息队列-内核的链表
4.信号量-计数器
5.共享内存
6.内存映射
7.套接字
2.无名管道
2.1.管道的概念
-
本质
- 内核缓冲区
- 伪文件-不占用磁盘空间
-
特点:
- 两部分:
- 读端,写端,对应两个文件描述符
- 数据写端流入,读端流出
- 操作管理的进程被销毁之后,管道自动被释放
- 管道默认是阻塞的
- 两部分:
2.2.管道的原理
- 内部实现方式:队列
- 环形队列------>便于数据读取
- 特点:先进先出
- 缓冲区大小
- 默认4K
- 大小会根据实际情况做适当调整
2.3管道的局限性
- 队列:
- 数据只能读取一次,不能重复读取
- 半双工:
- 单工:遥控器
- 半双工:对讲机
- 数据传输方向是单向的
- 双工
- 匿名管道
- 适用于有血缘关系的进程
2.4.创建匿名管道
int pipe(int fd[2])
fd‐传出参数:
fd[0]‐读端----3
fd[1]‐写端----4
返回值:
0:成功
‐1:创建失败
2.5.父子进程使用管道通信
-
实现 ps aux| grep “bash”
-
数据重定向:dup2
2.6.管道的读写行为
-
读操作
- 有数据
- read(fd[1])正常读,返回读的字节数
- 无数据
- 写端被全部关闭,read返回0,相当于文件被读到尾部
- 写端未被全部关闭
- read被阻塞
- 有数据
-
写操作
- 读端被全部关闭
- 管道破裂,进程被终止(就如同水管一端不停地进水另一端不出水水管迟早被撑爆)
- 内核给当前进程发送信号SIGPIPE-13,默认处理动作
- 管道破裂,进程被终止(就如同水管一端不停地进水另一端不出水水管迟早被撑爆)
- 读端未被全部关闭
- 缓冲区写满了
- writezuse
- 缓冲区未写满
- write继续写,直到写满为止
- 缓冲区写满了
- 读端被全部关闭
-
如何设置非阻塞?
- 默认读写两端都阻塞
- 设置读端为非阻塞pipe(fd)
- fcntl-变参函数
- 复制文件描述符-dup
- 修改文件属性-open的时候对应flag属性
- 设置方法
- fcntl-变参函数
//获取原来的flags
int flags = fcntl(fd[0],F+GETFL);
//设置新的flags
flag |=O_NONBLOCK;
fcntl(fd[0],F_SETFL,flags);
fcntl(fd[0],F_SETFL,flags);
2.7.查看管道缓冲区大小
-
命令
- ulimit -a
-
fpathconf
父子进程通过管道通信
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int fd[2];
if(pipe(fd))
{
printf("create pipe failed\n");
return -1;
}
printf("create pipe successed\n");
pid = fork();
if(pid == -1)
{
printf("create process failed\n");
return -2;
}
else if(pid > 0)
{
close(fd[0]);
dup2(fd[1],STDOUT_FILENO);//将管道的写端重定义从终端写入
execlp("ps","ps","aux",NULL);//让父进程执行ps aux 的命令并把数据写到管道
}
else if(pid == 0)
{
close(fd[1]);
dup2(fd[0],STDIN_FILENO);//将管道的读出重定义为读到终端
execlp("grep","grep","bash",NULL);//子进程执行grep bash命令筛选父进程写入的数据并显示到终端
}
return 0;
}
3.有名管道
//函数形式:
int mkfifo(const char \*filename,mode_t mode);
/*
*function:创建管道文件
*param:管道文件文件名,权限,创建的文件权限仍然和umask有关系。
*return:创建成功返回0,创建失败返回-1。
*/
3.1.特点
有名管道
在磁盘上有这样一个文件 ls -l ->p
也是一个伪文件,在磁盘大小永久为0
数据存在内核中有一个对应的缓冲区
半双工通信方式
3.2.使用场景
没有血缘关系的进程间通信
3.3.创建方式
-
命令:mkfifo 管道名
-
函数:mkfifo
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
int ret;
ret = mkfifo("./myfifo",0777);
if(ret == -1)
{
printf("create myfifo failed\n");
return -1;
}
return 0;
}
3.4.fifo文件可以使用io函数进程操作
-
open/close
-
read/write
-
不能执行lseek操作
//read_fifo
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int ret;
int fd;
char ReadBuf[50] = {0};
ret = mkfifo("./myfifo",0777);//创建有名管道
if(ret == -1)
{
printf("make fifo failed\n");
return -1;
}
fd = open("./myfifo",O_RDONLY);//打开有名管道
if(fd == -1)
{
printf("open file failed\n");
return -1;
}
ret = read(fd,ReadBuf,50);//读有名管道的内容
printf("read %d byte is %s",ret,ReadBuf);
close(fd);
return 0;
}
//write_fifo
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
int ret;
int fd;
char *str = "hello world";//预定要发送的内容也可以设置从控制终端读
fd = open("./myfifo",O_WRONLY);
if(fd == -1)
{
printf("open file failed\n");
return -1;
}
ret = write(fd,str,strlen(str));//写数据
if(ret == -1)
{
printf("write error\n");
return -1;
}
close(fd);
return 0;
}
标签:return,int,通信,ret,管道,fd,linux,------,include
From: https://blog.csdn.net/qq_63556165/article/details/141276642