目录
1. IPC
1.1 IPC 概念
Inter Process Communication 进程间通信。
1.2 进程间通信常用的几种方式
- 1,管道通信:有名管道,无名管道
- 2,信号 - 系统开销小
- 3,消息队列 - 内核的链表
- 4,信号量 - 计数器
- 5,共享内存
- 6,内存映射
- 7,套接字
2. 匿名管道(PIPE)
2.1 管道的概念
本质:
- 内核缓冲区
- 伪文件-不占用磁盘空间
特点:
- 读端,写端,对应两个文件描述符 fd[0]、fd[1]
- 数据写端流入,读端流出
- 操作管理的进程被销毁之后,管道自动被释放
- 管道默认是阻塞的
2.2 管道的局限性
队列:数据只能读取一次,不能重复读取
半双工:读端操作的时候写端不能操作,写端操作的时候读端不能操作。
2.3 创建匿名管道
int pipe(int fd[2])
fd ‐ 传出参数:
fd[0] ‐ 读端
fd[1] ‐ 写端
返回值:
0:成功
‐1:创建失败
2.4 管道的读写
2.4.1 读操作
- 有数据:read(fd[1]) 正常读,返回读出的字节数
- 无数据:写端被全部关闭:read 返回0,相当于读文件到了尾部。没有全部关闭:read 阻塞
2.4.2 写操作
- 读端全部关闭:管道破裂,进程被终止。内核给当前进程发送信号SIGPIPE-13,默认处理动作
- 读端没全部关闭:缓冲区写满了:write阻塞。缓冲区没满:write继续写,直到写满,阻塞
2.5 父子进程使用管道通信
2.5.1 实现 ps aux| grep "bash"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int ret;
int fd[2];
ret = pipe(fd); // 创建匿名管道
if (ret == -1)
{
printf("create pipe failed!~\n");
exit(1);
}
pid_t pid = fork(); // 创建父子进程
if (pid == -1)
{
printf("fork failed!~");
exit(1);
}
// 父进程 执行 ps aux
if (pid > 0)
{
close(fd[0]); // 操作写端要先关闭读端
dup2(fd[1], STDOUT_FILENO); // 把原本输出在 STDOUT 的内容重定向至管道写端
execlp("ps", "ps", "aux", NULL);
perror("execlp");
exit(1);
}
// 子进程 执行 grep "bash"
else if (pid == 0)
{
close(fd[1]); // 操作读端要先关闭写端
dup2(fd[0], STDIN_FILENO); // 把原本输出在 STDIN 的内容重定向至管道读端
execlp("grep", "grep", "bash", "--color=auto", NULL);
perror("execlp");
}
close(fd[0]);
close(fd[1]);
return 0;
}
2.5.2 运行结果
程序运行结果和在终端直接写入 ps aux | grep bash 的效果一致。
3. 有名管道 (FIFO)
3.1 函数原型
int mkfifo(const char *filename,mode_t mode);
- 功能:创建管道文件
- 参数:管道文件文件名,权限,创建的文件权限仍然和umask有关系。
- 返回值:创建成功返回0,创建失败返回-1。
3.2 特点
- 在磁盘上有这样一个文件 ls -l ->p
- 也是一个伪文件,在磁盘大小永久为0
- 数据存在内核中有一个对应的缓冲区
- 半双工通信方式
3.3 使用场景
- 没有血缘关系的进程间通信
3.4 fifo 文件可以使用 io 函数进程操作
- open/close
- read/write
- 不能执行 lseek 操作
3.5 fifo 案例实现两进程通信
mkfifo.c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret;
int fd;
int nread;
char readBuf[50] = {0};
ret = mkfifo("/home/outside/03_IPC/myfifo", 0777); // 创建 fifo
if (ret == -1)
{
perror("mkfifo");
return -1;
}
else
{
printf("creat fifo succeed!~\n");
}
fd = open("./myfifo", O_RDONLY); // 打开 fifo
if (fd < 0)
{
perror("fd");
return -1;
}
else
{
printf("open fifo succeed!~\n");
}
nread = read(fd, readBuf, sizeof(readBuf)); // 读取 fd 的内容到 readBuf 内
printf("read %d byte from fifo %s:\n", nread, readBuf);
close(fd);
return 0;
}
write.c
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
char *str = "Hello World!~";
int fd;
fd = open("./myfifo", O_WRONLY);
if (fd < 0)
{
perror("fd");
return -1;
}
else
{
printf("open fifo succeed!~\n");
}
write(fd, str, strlen(str)); // 把 str 指向的字符串写入 fd 内
close(fd);
return 0;
}
程序运行结果:
实现 fifo 的创建与两进程间通信。