• 【操作系统】9/35MMAP


    内存共享映射(MMAP)

    用户层调用一个模块,叫MMAP。memory map socket

    会给我们申请一块内存空间,这块空间叫:映射内存。

    但是要用mmap,先要要求本地磁盘有一个文件:映射文件。例如testdate

    映射内存大小与映射文件一致。内容也是一致的。映射可以理解为拷贝。

    通过mmap,将映射文件,映射到映射内存里。

    有两种方式来进行映射:私有、共享。通过两种方式的任意一种,来映射到映射内存当中。

    私有映射:MAP_PRIVATE

    将映射文件原封不动的拷贝一份,给映射内存。单纯的拷贝,采用简单的拷贝。

    互不影响了,互相独立。某一份修改,不会影响其他内容。

    共享映射:MAP_SHARE

    sync同步机制。

    无论对其中的哪一份修改,都会全部修改。同步给数据块。

    通过MMAP方式进行通信

    A做mmap映射,b也是一样的操作,都进行sync共享映射。

    因此,两个映射内存和映射文件,三者都是相同的,这就是进程间通信。

    MMAP头文件和接口

    void * ptr = mmap(void * ptr, int size, int prot, int how, int fd, ssize_t offset);六个参数

    • ptr传NULL,可以自己申请一块空间然后交给ptr,如果是NULL,mmap会自行申请映射内存,也允许用户自己申请
    • size传NULL,内存里不能写0,就必须是NULL
    • prot映射内存权限,PROT_READ(读),PROT_WRITE(写),PROT_EXEC(执行),PROT_NONE(未知)
    • how映射方式,MAP_PRIVATE和MAP_SHARE
    • fd映射文件描述符,预先打开映射文件
    • offset映射偏移量,如果不便宜,传0即可。内存单位是Page,按内存页分配的。按内存页单位偏移
    • return value,如果成功返回映射内存地址,如果失败返回错误关键字,MAP_FAILED

    munmap(void* ptr, int size)用于销毁释放映射内存。

    对测试文件进行共享映射,映射成功后修改映射内存,实现同步修改映射文件。

    将mapfile文件中的前四个字节(int*)的内容变为1234,而字符串1234的十六进制表示就是ptr[0]。

    可以利用od -tcx 来拆分文本。

    通过mmap间接修改文件内容

    一个用户,想去篡改文件,一个重要的系统文件,首先对文件要有权限。

    other用户,对这个文件只有最低权限,-rw-rw-r--,仅有只读权限。

    那么,通过mmap共享映射系统文件,然后修改共享内存,能否实现其他用户修改系统文件?

    如果能成,系统就无安全可言了,系统权限变得没有意义,权限保护形同虚设。

    mmap不是看用户是谁,而是看如何打开。

    如果一个用户想对一个文件进行映射,映射的权限参考打开权限

    就是看你是只读还是写的方式打开的。

    mmap实现进程通信

    假设写端的映射内存是结构体。

    对于映射文件,做一个空文件拓展。

    写端每隔一秒,编辑一次映射内存的结构体。

    修改之后马上同步至映射文件和读端映射内存。

    这样读端就间隔一秒读出。

    mmap读写端通信例子

    就是在写端设置空文件,然后通过截断的方式拓展文件。

    然后以mmap形式进行通信,对于结构体中的id每隔一秒进行一次修改。

    读端不需要截断,并且不需要赋初值。

    而例如id从0开始,读的结果也不一定是从0开始,因为:映射文件大小为一个结构体大小,所以不能缓存多个数据包。

    一边写一边读。

    unlink函数:使用之后,删除映射文件。

    用户读取磁盘流程

    例如用户要定义一个buffer缓冲区,然后读取一个文件(其实在磁盘中)

    首先通过探针寻址的方式,硬盘外部有一个DMA快速缓存设备,用来读取缓存。

    DMA读取磁盘里文件内容,读取之后,进行第一次拷贝:DMA中拷贝至内核缓冲区。

    第二次拷贝:内核缓冲区拷贝至buffer的用户缓冲区。用户read磁盘的文件过程。

    mmap适用

    mmap零拷贝,相比传统读取数据,速度更快,开销更小。

    mmap没有内核缓冲区到用户缓冲区的过程的,mmap使用之后,直接是内核缓冲区向内核缓冲区进行映射。节省了开销。比较受欢迎。

    读取网络数据用的也多。

    磁盘位置就变成了网卡,网络设备。

    还是DMA,然后就变成了socket缓冲区。

    处理大文件,mmap合适

    大文件可能存不下,不可能一次读到缓冲区里,可以采用:分段映射。

    一次映射文件的一部分。block分块,每次映射一块。

    采用mmap偏移映射,进行分段映射。

    void* ptr=mmap(NULL, 4096, READ, PRIVATE, int fd, 0);第一次是0,下一次就是4096往上加了。

    如果觉得太慢,可以用多线程。

  • 相关阅读:
    实验18.RIP路由引入
    Pytorch模型量化
    Java练习20
    用 Golang 采集 Nginx 接口流量大小
    有刷与无刷电机的原理
    ubuntu下网卡插入网线后仍然不连接
    [AUTOSAR][诊断管理][$11] 复位服务
    WEB安全基础 - - -弱口令和暴力破解
    基于vue+MySQL的外包项目信息系统
    Centos 64位环境下编译32位C程序
  • 原文地址:https://blog.csdn.net/callmejielun/article/details/126258736