进程间的通信就像两人的交流,需要一个“公共场所”常见的有1、内核 2、内存 3、磁盘。
mmap
- 用途:进程间的通信
- 使用原理:把磁盘的一个空间映射到内存中,如下图所示
- 函数:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
- 参数解析
-
参数1:希望在内存的哪个位置(即内存地址),传NULL,由系统自动找一块内存空间。一般都写NULL
-
参数2:请内存长度(可以使用lseek函数来测试文件大小)
-
参数3:prot页面属性(映射到内存的这一段的权限),就是对这个文件是要读还是写,可以填写的参数为:
- PROT_EXEC表示映射的这一段可执行,例如映射共享库
- PROT_READ表示映射的这一段可读
- PROT_WRITE表示映射的这一段可写
- PROT_NONE表示映射的这一段不可访问
-
参数4:状态标志,有两种:共享映射MAP_SHARED 和 私有映射MAP_PRIVATE
- 共享映射MAP_SHARED:多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。 (即,我这个进程修改了一个地方,其他进程也看得到)
- 私有映射MAP_PRIVATE:多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
-
参数5:文件操作符
-
参数6:偏移量
-
- 返回值:如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED
mmap的注意事项:
1、用于进程之间通信,一般设计成结构体,用于传输数据
2、进程间通信,一般设计成临时文件(读完删除使用unlink)
3、当有总线出错,优先查看共享文件是否有存储空间
4、如果段出错可能是使用到了,还没创建的文件(或者是不存在的文件)
示例文件
写文件端
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define MAPLEN 0x1000 //这个我来定义文件的大小,一会要映射到内存
//定义一个学生的结构体
struct STU
{
int ID;
char name[64];
char sex;
};
//定义一个函数,专门来输出进程执行时的错误
void sys_err(char *str,int exitno)
{
perror(str);
exit(exitno);
}
/*
你要先要创建一个hello文件,不然一会执行的时候会报段出错
使用mmap来修改文件信息
*/
//文件写成传参的形式
int main(int argc,char *argv[])
{
//创建一个文件结构体变量
struct STU *mm;
int fd,i=0;
if(argc < 2)
{
printf("enter your name\n");
exit(1);
}
//执行时输入的文件名,会在这里打开
fd = open(argv[1],O_RDWR|O_CREAT,0777);
//如果打开失败
if(fd<0)
{
//报错
sys_err("open",1);
}
//写入一个“\0”,来扩展文件,让文件由存储空间,不写这下面两个if会报总线错误
if(lseek(fd,MAPLEN-1,SEEK_SET)<0)
{
sys_err("mmsp",3);
}
if(write(fd,"\0",1)<0)
{
sys_err("write",4);
}
//MAPLEN是我上面的宏定义
mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mm == MAP_FAILED)
{
sys_err("mmsp",2);
}
close(fd);
while(1)
{
mm->ID = i;
sprintf(mm->name,"zhaozhao - %d",i++);
if(i%2 == 0)
{
mm->sex = 'm';
}
else
{
mm->sex = 'w';
}
sleep(1);
}
//关闭映射
munmap(mm,MAPLEN);
return 0;
读文件端
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define MAPLEN 0x1000
struct STU
{
int ID;
char name[64];
char sex;
};
void sys_err(char *str,int exitno)
{
perror(str);
exit(exitno);
}
int main(int argc,char *argv[])
{
struct STU *mm;
int fd,i=0;
if(argc < 2)
{
printf("enter your name\n");
exit(1);
}
//打开文件,只读模式
fd = open(argv[1],O_RDWR);
if(fd < 0)
{
sys_err("open",1);
}
mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(mm == MAP_FAILED)
{
sys_err("mmsp",2);
}
close(fd);
//读完删除文件,防止创建多个文件
nulink(argv[1]);
while(1)
{
printf("%d\n",mm->ID);
printf("%s\n",mm->name);
printf("%c\n",mm->sex);
sleep(1);
}
//关闭
munmap(mm,MAPLEN);
return 0;
}
在写端执行文件的的时候,输入文件名称(没有创建过的文件),在执行读端的时候输入参数(前面创建的文件名称)这样在终端上就能看见读取的数据。