MMAP-存储映射I/O

存储映射I/O 介绍

    存储映射IO(Memory-mapped I/O) 使用一个磁盘文件与存储空间的一个缓冲区相映射。于是当缓冲区中取出数据,就相当于读文件中的相应字节。于此类似。间数据存入缓冲区,则相应的字节就会自动写入文件。因为数据已经写入文件,即使机器重启数据还在。


TIM截图20190517162610.png

mmap函数

    使用这种方法,首先应通知内核,间一个指定文件映射到存储区域中。可以通过mmap函数来实现。

函数原型 :
    void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset); 
参数:
    addr:建立映射区的首地址,有Linux内核指定。使用时传NULL即可
    length:与创建映射取的大小
    prot: 映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
    flags:标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
            MAP_SHARED:  会将映射区所做的操作反映到物理设备(磁盘)上。
            MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
   fd: 用来建立映射区的文件描述符
   offset: 映射文件的偏移(4k的整数倍)

munmap函数

当不需要这个映射内存时通过munmap函数来释放

函数原型:
    int munmap(void *addr, size_t length);
参数:
    addr :mmap的返回值
    length:释放区域的长度

示例代码

mem.txt文件

jjjjjjjj

mmap.c文件

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int fd = open("mem.txt",O_RDWR);//创建并且截断文件
    //int fd = open("mem.txt",O_RDWR|O_CREAT|O_TRUNC,0664);//创建并且截断文件


    //创建映射区
   char *mem = mmap(NULL,20,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    //char *mem = mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);

    if(mem == MAP_FAILED){
        perror("mmap err");
        return -1;
    }
  
    //拷贝数据
    strcpy(mem,"helloworld");
//    mem++;
    //释放mmap
    if(munmap(mem,20) < 0){
        perror("munmap err");
    }
    close(fd);
    return 0;
}

运行代码之后,发现mem.txt文件内容已经改变

[root@VM_0_11_centos linux]# cat mem.txt
helloworl[root@VM_0_11_centos linux]#

**读写例 **

#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct _Student{
    int sid;
    char sname[20];
}Student;

int main(int argc,char *argv[])
{
    //open file 
    int fd = open(argv[1],O_RDWR);
    //mmap 
    int length = sizeof(Student);
    Student *stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(stu == MAP_FAILED){
        perror("mmap err");
        return -1;
    }
    //read data 
    while(1){
        printf("sid=%d,sname=%s\n",stu->sid,stu->sname);
        sleep(1);
    }
    //close and munmap 
    munmap(stu,length);
    close(fd);
    return 0;
}

写示例

#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct  _Student{
    int sid;
    char sname[20];
}Student;

int main(int argc,char *argv[])
{
    if(argc != 2){
        printf("./a.out filename\n");
        return -1;
    }
    
    // 1. open file 
    int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
    int length = sizeof(Student);

    ftruncate(fd,length);

    // 2. mmap
    Student * stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    
    if(stu == MAP_FAILED){
        perror("mmap err");
        return -1;
    }
    int num = 1;
    // 3. 修改内存数据
    while(1){
        stu->sid = num;
        sprintf(stu->sname,"xiaoming-%03d",num++);
        sleep(1);//相当于没隔1s修改一次映射区的内容
    }
    // 4. 释放映射区和关闭文件描述符
    munmap(stu,length);
    close(fd);

    return 0;
}

map的一些问题

1.如果对mem越界操作会怎样?

多出的数据会丢失,尽量避免这样的操作

2.如果文件描述符向关闭,对mmap映射有没有影响

没有影响

3.open的时候,可以新创建一个文件来创建映射区吗?

不可以,使用的文件大小不能为0

4.如果文件偏移随便填一个数会怎么样?

运行时会报错

匿名映射

     通过使用我们发现,使用映射区来完成文件读写十分方便,赋值进程通信也比较容易。但是缺陷是,每次创建映射区一定要依赖一个文件才能实现。通常为了建立映射区要open一个temp文件,创建好了再unlink,close掉,比较麻烦。可以直接使用匿名映射来代替。Linux系统给我们提供了创建匿名映射区的方法,无需依赖一个文件,即可创建映射取。同样需要借助标志位参数flags来指定。
示例代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    //修改创建的参数
    int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);

    if(mem == MAP_FAILED){
        perror("mmap err");
        return -1;
    }
    ...

你可能感兴趣的:(MMAP-存储映射I/O)