Linux进程通信之mmap
mmap()函数:
void *mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset);
返回:成功:返回创建的映射区首地址;失败:MAP_FAILED 宏
参数:
addr: 建立映射区的首地址,由linux内核决定。使用时直接传递NULL;
length: 欲创建映射区的大小
port: 映射区权限PROT _READ、PROT_WRITE 、PROT _READ|PROTWRITE
flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
MAP_SHARED: 会将映射区所做的操作反射到物理设备上
MAP_PRIVATE: 映射区所作的修改不会反映到物理设备。
fd: 用来建立映射区的文件描述符
offset: 映射文件的偏移(4K的整数倍)
/***
mmap.c
***/
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h> int main()
{
int len,ret;
char *p = NULL;
int fd = open("mytest.txt",O_CREAT|O_RDWR,);
if(fd < )
{
perror("open error:");
exit();
}
len = ftruncate(fd,);
if(- == len)
{
perror("ftruncate error:");
exit();
}
p = mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error:");
exit();
}
strcpy(p,"abc"); ret = munmap(p,);
if(- == ret)
{
perror("mmap error:");
exit();
}
close(fd);
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap.c -o mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ cat mytest.txt
abc
mmap在使用过程中注意以下事项:
- 创建映射区的过程中,隐含着一次对映射文件的读操作。
- 当MAP_SHARED时,要求:映射区的权限 <= 文件打开的权限(出于对映射区的保护)。而MAP_PRIVATE则无所谓,因为mmap中的权限时对内存的限制。
- 映射区的释放和文件关闭无关。只要映射成功,文件可以立刻关闭。
- 特别注意:当映射文件大小为0时,不能创建映射区。所以:用于映射的文件必须有实际大小。mmap使用时常常会出现总线错误,通常是因为共享文件存储空间大小所引起的。
- munmap传入的地址一定是mmap的返回地址,坚决杜绝指针++操作
- 如果使用文件偏移,则值必须是4K的整数倍
- mmap创建映射区出错概率极高,一定要检查返回值,确保映射区建立成功再进行后续操作。
mmap父子进程间通信:
文件inode属性
struct stat
{
存储指针地址;
大小;
权限;
类型;
所以者;
}
/***
mmap_fork.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid; int fd;
fd = open("temp",O_RDWR|O_CREAT|O_TRUNC,);
if(fd < )
{
perror("open error");
exit();
}
unlink("temp");
ftruncate(fd,); p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
}
close(fd); pid = fork();
if( == pid)
{
*p = ;
var = ;
printf("child, *p = %d, var = %d\n",*p,var);
}
else
{
sleep();
printf("parent, *p = %d, var = %d\n",*p,var);
wait(NULL); int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap_fork.c -o mmap_fork
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap_fork
child, *p = 2000, var = 1000
parent, *p = 2000, var = 100
mmap创建匿名映射区
/***
fork_mmap_linux.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid; p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANON,-,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
} pid = fork();
if( == pid)
{
var = ;
*p = ;
printf("child, *p = %d,var = %d\n",*p,var);
}
else
{
sleep();
// printf("parent,*p = %d\n",*p);
printf("child, *p = %d,var = %d\n",*p,var);
wait(NULL);
int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map_linux.c -o fork_map_linux
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map_linux
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
注意:MAP_ANONYMOUS和MAP_ANON 这两个宏是linux操作系统特有的宏,再类Unix系统中如无该宏的定义,可以使用以下步骤来完成匿名映射区的建立。
- fd = open(“/dev/zero”,O_RDWR);
- p = mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
/***
fork_map_anon.c
***/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h> int var = ; int main()
{
int *p;
pid_t pid;
int fd = open("/dev/zero",O_RDWR); p = (int*)mmap(NULL,,PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(p == MAP_FAILED)
{
perror("mmap error");
exit();
} pid = fork();
if( == pid)
{
var = ;
*p = ;
printf("child, *p = %d,var = %d\n",*p,var);
}
else
{
sleep();
// printf("parent,*p = %d\n",*p);
printf("child, *p = %d,var = %d\n",*p,var);
wait(NULL);
int ret = munmap(p,);
if(- == ret)
{
perror("munmap error");
exit();
}
}
return ;
}
运行结果:
buntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map.c -o fork_map
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
mmap无血缘关系进程间通信:
/***
mmap_w.c
***/
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<string.h> struct STU
{
int id;
char name[];
char sex;
}; void sys_err(char *str)
{
perror(str);
exit();
} int main(int argc,char ** argv)
{
int fd;
struct STU student = {,"xiaoming",'m'};
char *mm; if(argc < )
{
printf("./a.out file_shared\n");
exit(-);
} fd = open(argv[],O_RDWR | O_CREAT,);
ftruncate(fd,sizeof(student)); mm = mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,);
if(mm == MAP_FAILED)
{
sys_err("mmap error");
} close(fd); while()
{
memcpy(mm,&student,sizeof(student));
student.id++;
sleep();
} munmap(mm,sizeof(student));
return ;
}
/***
mmap_r.c
***/
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<string.h> struct STU
{
int id;
char name[];
char sex;
}; void sys_err(char *str)
{
perror(str);
exit();
} int main(int argc,char ** argv)
{
int fd;
struct STU student;
struct STU *mm; if(argc < )
{
printf("./a.out file_shared\n");
exit(-);
} fd = open(argv[],O_RDONLY);
if(- == fd)
sys_err("open error"); mm = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,);
if(mm == MAP_FAILED)
{
sys_err("mmap error");
} close(fd); while()
{
printf("id=%d,name = %s,%c\n",mm->id,mm->name,mm->sex);
sleep();
} munmap(mm,sizeof(student));
return ;
}
Linux进程通信之mmap的更多相关文章
- linux 进程通信之 mmap
一,管道PIPE 二,FIFO通信 三,mmap通信 创建内存映射区. #include <sys/mman.h> void *mmap(void *addr, size_t length ...
- Linux进程通信----匿名管道
Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...
- Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存. 所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...
- Linux进程通信学习总结
http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念 引用标识符:引用标识符是一个整数,表示每一个SYSV ...
- Linux进程通信的几种方式总结
进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...
- linux进程通信之管道
1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...
- linux 进程通信之 共享内存
共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...
- linux 进程通信之 信号
一,管道PIPE 二,FIFO通信 三,mmap通信 四,信号的概念 信号的特点:简单,但不能携带大量的信息,满足特定条件就会发生 信号的机制:进程B发送信号给进程A.信号是由内核来处理的. 信号的产 ...
- linux进程通信
e14: 进程间通信(进程之间发送/接收字符串/结构体): 传统的通信方式: 管道(有名管道 fifo,无名管道 pipe) 信号 signal System V(基于IPC的对象): ...
随机推荐
- css之word-wrap和word-break的区别
对于英文单词,如果有一个连写且长度很长的英文单词,在第一行显示不下的情况下,浏览器默认不会截断显示,而是把这个单词整体挪到下一行.但是当整体挪到下一行还是显示不完全该肿么办呢?有如下两个方法: wor ...
- Core使用SAP Web Service
.Net Core在使用SAP的Web Service会遭遇到一些错误,貌似目前并不支持SAP中的Web Service,我们需要曲线实现下调用过程: 经测试,不再需要Framework项目中转,Sy ...
- js文件分段上传
前端代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/T ...
- oracle 数据库 主键索引重建
oracle 数据库 主键索引重建 alter table table_name drop primary key; alter table table_name add constraint pk_ ...
- C#获取客户端Ip工具类
string pcname = Dns.GetHostName(); string ip = Dns.GetHostAddresses(pcname).First().ToString(); usin ...
- 使用IP代理初体验
在很多时候我们需要用到IP代理,比如爬虫.投票等 封IP是一种很常用的办法,所谓道高一尺.魔高一丈,IP代理应运而生 最简单的一段代码 static void Main(string[] args) ...
- SSRF(服务端请求伪造)
- 基于【 Docker】三 || Docker的基本操作
一.Docker常用命令 1.搜索镜像:docker search 镜像名称 2.下载镜像:docker pull 镜像名称:版本号 3.查看镜像:docker images 4.删除镜像:docke ...
- vs Code编辑器智能提示功能
一.Node.Js的Typings工具可以用于Visual Studio Code的代码补全 1.vscode 的默认只有es原声api带有自动补全的功能,现在V1.9的版本默认已经支持NodeJS的 ...
- 为什么加了jquery mobile 会有 Loading 字样在页面底部?【已解决】
这是一个奇怪的问题,用了jquery mobile js库,页面底部就会出现Loading字样, 解决办法如下: 1,正常加上css样式 2,一定要在jquery mobile js库加载之前,设置 ...