首页 > 编程知识 正文

进程到进程之间的通信(进程间的高级通信机制)

时间:2023-05-05 04:33:09 阅读:77069 作者:3940

进入drdxmf

1学习目标

熟练使用pipe亲子进入drdxmf

熟练使用pipe兄弟进入drdxmf

熟练使用fifo进入无血缘关系的drdxmf

使用mmap进入血缘关系的drdxmf

使用mmap进入无血缘关系的drdxmf

二进制drdxmf相关概念

2.1什么是进入drdxmf

在Linux环境中,进程地址空间是相互独立的,每个进程有不同的用户地址空间。 就任

进程和进程之间无法相互访问,因为一个进程的全局变量在另一个进程中不可见。

要交换数据,必须通过内核,在内核中打开缓冲区,并且进程1必须从用户空间复制数据

内核缓冲器,进程2从内核缓冲器读取数据。 内核提供的此机制称为先进drdxmf (称为IPC )。

互处理通信)。

2.2进入drdxmf的方式

要在进程之间完成数据传输,必须在操作系统上提供特殊方法,如文件、管道和信号。

共享内存、消息队列、套接字、命名管道等。 随着计算机的繁荣,一些方法

设计缺陷要么被淘汰,要么被抛弃。 目前常用的访问drdxmf的方法如下。

管道(最容易使用) ) ) ) )。

信号(开销最小) ) ) )。

共享地图区域(无血缘关系) ) )

本地套接字(最稳定)

3管路-pipe

3.1管道概念

管道是最基本的IPC机制,也称为匿名管道,应用于有血缘关系的过程之间,直到结束

数据传输。 调用pipe函数将创建管道。

这些特质包括:

管道的本质是内核缓冲区

由两个文件描述符引用,一个表示读取端,另一个表示写入端。

规定数据从管道的写入侧流入管道,数据从读取侧流出。

两个过程结束后,管道也自动消失。

缺省情况下,管道的读取端和写入端被阻止。

3.2管路原理

管道的本质是内核缓冲器,内部使用环形队列实现。

缺省缓冲区大小为4K,可以使用ulimit -a命令获取大小。

在实际操作过程中,缓冲区将根据数据压力进行适当调整。

3.3管道极限

一旦读取了数据,它就不存在于管道中,不能重复读取。

数据只能沿一个方向流动,必须使用两个管道才能双向流动

管道只能在有血缘关系的过程之间使用。

3.4创建管道-pipe函数

函数作用:

创建管道

函数原型:

intpipe(intFD[2];

函数参数:

如果函数调用成功,fd[0]存储管道的读取侧,fd[1]存储管道的写入侧

返回值:

成功回归0;

失败返回-1,设定错误值。

函数调用成功地返回读取端和写入端文件描述符。 其中,软盘[0]为读取侧,软盘[1]为写入侧

使用这两个文件描述符读取和写入管道数据,管道的本质是操作内核缓冲区。

成功创建管道后,创建管道的进程(父进程)将同时了解管道的读取侧和写入侧。

如何实现亲子进军drdxmf?

3.5亲子进程使用管道进行通信

一个过程在pipe ()创建管道后,通常fork另一个子过程,通过管道实现父子关系

进程之间的通信(因此,只要两个进程有血缘关系,这里的血缘关系就是

有共同的祖先,都可以通过流水线方式通信)。 父子进程之间有相同的文件描写

符号(指向同一管道pipe ),其他无关进程无法检索由pipe ()生成的两个文件

描述符也不能使用同一管道进行通信。

步骤1 :父进程创建管道

步骤2 :父进程fork从子进程中退出

步骤3 :父进程关闭软盘[0],子进程关闭软盘[1]

创建步骤总结:

父进程调用pipe函数创建管道,得到指向每个管道的两个文件描述符fd[0]和fd[1]

管道的读取侧和写入侧。

当父进程调用fork创建子进程时,子进程也有两个指向同一管道的文件描述符。

父进程关闭管道引线,子进程关闭管道。 父进程可以将数据写入管道。

子进程可以通过读取管道中的数据来父子进入drdxmf。

3.6管道练习

在一个过程中可以使用管道完成读写操作吗?

使用管道亲子进入drdxmf吗?

父子进入drdxmf,实现ps aux | grep bash

使用execlp和dup2函数

兄弟进入drdxmf,实现ps aux | grep bash

使用execlp和dup2函数

父进程调用waitpid函数完成子进程的回收

3.7管道读写行为

读取操作

有数据

read正常读取,返回读取的字节数

无数据

写入侧全部关闭

read解除块并返回0,意味着读取了文件并读到了末尾

没有全部关闭

读取块

写入操作

 读端全部关闭
管道破裂,进程终止, 内核给当前进程发 SIGPIPE 信号
 读端没全部关闭
 缓冲区写满了
write 阻塞
 缓冲区没有满
继续 write
3.8 如何设置管道为非阻塞
默认情况下,管道的读写两端都是阻塞的,若要设置读或者写端为非阻塞,则可参
考下列三个步骤进行:
第 1 步: int flags = fcntl(fd[0], F_GETFL, 0);
第 2 步: flag |= O_NONBLOCK;
第 3 步: fcntl(fd[0], F_SETFL, flags);
若是读端设置为非阻塞:
 写端没有关闭,管道中没有数据可读,则 read 返回-1;
 写端没有关闭,管道中有数据可读,则 read 返回实际读到的字节数
 写端已经关闭,管道中有数据可读,则 read 返回实际读到的字节数
 写端已经关闭,管道中没有数据可读,则 read 返回 0
3.9 如何查看管道缓冲区大小
 命令
ulimit -a
 函数
long fpathconf(int fd, int name);
printf(“pipe size==[%ld]n”, fpathconf(fd[0], _PC_PIPE_BUF));
printf(“pipe size==[%ld]n”, fpathconf(fd[1], _PC_PIPE_BUF));
4 FIFO
4.1 FIFO 介绍
FIFO 常被称为命名管道,以区分管道(pipe)。管道(pipe)只能用于“有血缘关系”的进
drdxmf。但通过 FIFO,不相关的进程也能交换数据。
FIFO 是 Linux 基础文件类型中的一种(文件类型为 p,可通过 ls -l 查看文件类型)。
但 FIFO 文件在磁盘上没有数据块,文件大小为 0,仅仅用来标识内核中一条通道。进程
可以打开这个文件进行 read/write,实际上是在读写内核缓冲区,这样就实现了进程间
通信。
4.2 创建管道
 方式 1-使用命令 mkfifo
命令格式: mkfifo 管道名
例如:mkfifo myfifo
 方式 2-使用函数
int mkfifo(const char *pathname, mode_t mode);
参数说明和返回值可以查看 man 3 mkfifo
当创建了一个 FIFO,就可以使用 open 函数打开它,常见的文件 I/O 函数都可用于
FIFO。如:close、read、write、unlink 等。
FIFO 严格遵循先进先出(first in first out),对 FIFO 的读总是从开始处返回数据,对
它们的写则把数据添加到末尾。它们不支持诸如 lseek()等文件定位操作。
4.3 使用 FIFO 完成两个进程通信
 使用 FIFO 完成两个进程通信的示意图
思路:
 进程 A:
 创建一个 fifo 文件:myfifo
 调用 open 函数打开 myfifo 文件
 调用 write 函数写入一个字符串如:“hello world”(其实是将数据写入到了内核
缓冲区)
 调用 close 函数关闭 myfifo 文件
 进程 B:
 调用 open 函数打开 myfifo 文件
 调用 read 函数读取文件内容(其实就是从内核中读取数据)
 打印显示读取的内容
 调用 close 函数关闭 myfifo 文件
注意:myfifo 文件是在进程 A 中创建的,如果先启动进程 B 会报错。思考一下如何解决
这个问题呢???
5 内存映射区
5.1 存储映射区介绍
存储映射 I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相
映射。从缓冲区中取数据,就相当于读文件中的相应字节;将数据写入缓冲区,则会将
数据写入文件。这样,就可在不使用 read 和 write 函数的情况下,使用地址(指针)完
成 I/O 操作。
使用存储映射这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映
射工作可以通过 mmap 函数来实现。
5.2 mmap 函数
 函数作用:
建立存储映射区
 函数原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
 函数返回值:
 成功:返回创建的映射区首地址;
 失败:MAP_FAILED 宏
 参数:
 addr: 指定映射的起始地址, 通常设为 NULL, 由系统指定
 length:映射到内存的文件长度
 prot: 映射区的保护方式, 最常用的:
 读:PROT_READ
 写:PROT_WRITE
 读写:PROT_READ | PROT_WRITE
 flags: 映射区的特性, 可以是
 MAP_SHARED: 写入映射区的数据会写回文件, 且允许其他映射该文件的
进程共享。
 MAP_PRIVATE: 对 映 射 区 的 写 入 操 作 会 产 生 一 个 映 射 区 的 复 制
(copy-on-write), 对此区域所做的修改不会写回原文件。
 fd:由 open 返回的文件描述符, 代表要映射的文件。
 offset:以文件开始处的偏移量, 必须是 4k 的整数倍, 通常为 0, 表示从文件头
开始映射。
5.3 munmap 函数
 函数作用:
释放由 mmap 函数建立的存储映射区
 函数原型:
int munmap(void *addr, size_t length);
 返回值:
成功:返回 0
失败:返回-1,设置 errno 值
 函数参数:
 addr:调用 mmap 函数成功返回的映射区首地址
 length:映射区大小(mmap 函数的第二个参数)
5.4 mmap 注意事项
 创建映射区的过程中,隐含着一次对映射文件的读操作,将文件内容读取到映射区
 当 MAP_SHARED 时,要求:映射区的权限应 <=文件打开的权限(出于对映射区的保
护)。而 MAP_PRIVATE 则无所谓,因为 mmap 中的权限是对内存的限制。
 映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。
 特别注意,当映射文件大小为 0 时,不能创建映射区。所以,用于映射的文件必须
要有实际大小;mmap 使用时常常会出现总线错误,通常是由于共享文件存储空间
大小引起的。
 munmap 传入的地址一定是 mmap 的返回地址。坚决杜绝指针++操作。
 文件偏移量必须为 0 或者 4K 的整数倍
 mmap 创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进
行后续操作。
5.5 有关 mmap 函数的使用总结
 第一个参数写成 NULL
 第二个参数要映射的文件大小 > 0
 第三个参数:PROT_READ 、PROT_WRITE
 第四个参数:MAP_SHARED 或者 MAP_PRIVATE
 第五个参数:打开的文件对应的文件描述符
 第六个参数:4k 的整数倍
5.6 mmap 函数相关思考题
 可以 open 的时候 O_CREAT 一个新文件来创建映射区吗?
 如果 open 时 O_RDONLY, mmap 时 PROT 参数指定 PROT_READ|PROT_WRITE 会怎样?
 mmap 映射完成之后, 文件描述符关闭,对 mmap 映射有没有影响?
 如果文件偏移量为 1000 会怎样?
 对 mem 越界操作会怎样?
 如果 mem++,munmap 可否成功?
 mmap 什么情况下会调用失败?
 如果不检测 mmap 的返回值,会怎样?
5.7 mmap 应用练习
 练习 1:使用 mmap 完成对文件的读写操作
 练习:2:使用 mmap 完成父子进drdxmf
 图解说明
 思路
 调用 mmap 函数创建存储映射区,返回映射区首地址 ptr
 调用 fork 函数创建子进程,子进程也拥有了映射区首地址
 父子进程可以通过映射区首地址指针 ptr 完成通信
 调用 munmap 函数释放存储映射区
 练习 3:使用 mmap 完成没有血缘关系的进程间通
思路:两个进程都打开相同的文件,然后调用 mmap 函数建立存储映射区,这
样两个进程共享同一个存储映射区。
使用 mmap 函数建立匿名映射:
mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。