Linux高阶——1026—验证内存映射&&mmap函数使用

1、验证共享映射后修改文件内容,是否能够同步

先创建一个映射文件,写入数据

分为四个步骤

1、打开映射文件

设文件描述符,使用open函数

int fd; 
if((fd=open("mapfile",O_RDWR))==-1)
{   
    perror("open failed");
    exit(0);
} 

获取文件大小,作为映射大小

int fsize;
fsize=lseek(fd,0,SEEK_END);

2、进行共享映射

int * ptr=NULL;
if((ptr=mmap(NULL,fsize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))==MAP_FAILED)
{
    perror("mmap failed");
    exit(0);
}

3、映射成功,关闭描述符

close(fd);

4、修改映射内存

munmap释放映射的函数

ptr[0]=0x34333231;
munmap(ptr,fsize);

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/fcntl.h>
#include<sys/mman.h>

int main()
{
    int fd; 
    if((fd=open("mapfile",O_RDWR))==-1)
    {   
        perror("open failed");
        exit(0);
    }   
    int fsize;
    fsize=lseek(fd,0,SEEK_END);
    int * ptr=NULL;
    if((ptr=mmap(NULL,fsize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))==MAP_FAILED)
    {
        perror("mmap failed");
        exit(0);
    }
    close(fd);
    ptr[0]=0x34333231;
    munmap(ptr,fsize);
    return 0;
}

成功截图

2、验证两个进程是否能够建立共享通信的方式

前提:必须保证映射文件是空的(保证不会出现还没有开始通信,但读端以及读到了数据的情况),但是需要有大小(否则无法映射)

使用ftruncate函数阶段,可以将文件大小变小或拓展空文件

写端

1、按照给对方的需求,定义一个结构体

typedef struct
{
    int id;
    char name[1024];

}shared_t;

2、创建文件

int fd=open("MAPIC",O_RDWR|O_CREAT,0664);

3、将文件截断

ftruncate(fd,sizeof(shared_t));

4、使用结构体指针进行映射

shared_t* ptr;
ptr=mmap(NULL,sizeof(shared_t),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

5、将结构体里的数据初始化

ptr->id=0;
bzero(ptr->name,1024);

6、循环写入数据

while(1)
{
    ++ptr->id;
    sprintf(ptr->name,"test message id %d",ptr->id);
    sleep(1);
}

7、 释放映射,关闭文件描述符

munmap(ptr,sizeof(shared_t));
close(fd);

总代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/fcntl.h>
#include<sys/mman.h>
#include<sys/types.h>

typedef struct
{
    int id;
    char name[1024];

}shared_t;

int main()
{
    int fd=open("MAPIC",O_RDWR|O_CREAT,0664);
    ftruncate(fd,sizeof(shared_t));
    shared_t* ptr;
    ptr=mmap(NULL,sizeof(shared_t),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ptr->id=0;
    bzero(ptr->name,1024);

    while(1)
    {
        ++ptr->id;
        sprintf(ptr->name,"test message id %d",ptr->id);
        sleep(1);
    }

    munmap(ptr,sizeof(shared_t));
    close(fd);
    return 0;
}

读端

读端只需要读即可

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/fcntl.h>
#include<sys/mman.h>
#include<sys/types.h>

typedef struct
{
    int id; 
    char name[1024];    
}shared_t;

int main()
{
    int fd=open("MAPIC",O_RDWR,0664);
    shared_t* ptr;
    ptr=mmap(NULL,sizeof(shared_t),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

    while(1)
    {   
        printf("%s\n",ptr->name);
        sleep(1);
    }

    munmap(ptr,sizeof(shared_t));
    close(fd);
    return 0;
}

3、mmap使用时容易出现的错误

1、映射权限错误

如果其他对某文件没有权限的人也通过映射的方式将文件修改了,则意味着无论是否有权限,任何人都能修改任何文件,为了避免此类现象,有两种措施

1、每次映射前先出进程查看用户权限,然后再决定映射方式,但这种方式效率低

2、mmap映射时,映射的权限要小于等于open的权限,因为如果用户对文件只有读权限,就无法以读写模式打开

2、映射大小错误

如果映射文件是一个空文件,则映射时会出现错误

如果将mmap函数的第二个参数改为4096,即指定比映射文件大的映射大小,虽然不会报错,但mmap返回的映射内存地址的指针无法使用

如果使用,则会访问越界,抛出总线错误,进程被杀死

如果申请的内存为1024,但权限比映射文件小,则系统给的读写权限为0

因此,能够获得的映射大小一般小于等于映射文件大小

4、MMAP一般使用的领域

1、大数据处理(大文件处理)

切割处理,可以采用mmap偏移分段映射

可以将1TB的文件使用mmap分割成为4K大小的文件分段处理

offset偏移量,只能为4K或4K的整数倍(按页偏移)

2、文件加载到进程内存,采用映射

相比传统的read,映射拷贝开销更小,效率更高,因为read,可能要读取多次

3、零拷贝

DMA,高速缓冲区,可以避免cpu拷贝,不占用CPU

内核缓冲区,是服务器的缓冲区,存在于电脑

标准发文件流程

当调用read时,系统将磁盘中的文件通过DMA拷贝到内核缓冲区,又通过CPU拷贝将文件拷贝到用户缓冲区buffer中------------2次上下文切换------1次CPU拷贝

当调用send函数时,会把用户缓冲区内的数据通过CPU拷贝到SOCKET缓冲区内,通过DMA拷贝到网卡设备中,通过网卡发出去,用户端等待接收下载------------2次上下文切换------1次CPU拷贝

标准发文件流程是4次切换开销,2次cpu拷贝开销

零拷贝的宗旨是减少拷贝,减少开销

mmap函数优化

4次切换,1次拷贝

SENDFILE

2次切换,1次拷贝

sendfile可以将内核缓冲区的数据使用CPU拷贝到SOCKET缓冲区内

相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’3 小时前
C++ list (链表)容器
c++·链表·list
----云烟----4 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024064 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it4 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康4 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神5 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++