011mmap进程通信
LINUX学习笔记
- mmap 进程通信
- 1. mmap 函数声明及头文件包含
- 1.1 参数说明
- 1.2 mmap 通信demo
- 2. mmap 注意事项:
- 2.1 mmap 函数的保险使用方法:
- 3. demo 父子进程间mmap通信
- 4. demo 非血缘关系进程间mmap通信
- 5. mmap通信与fifo和文件通信的差异
- 6. 匿名映射(只能用于血缘关系进程间通信)
mmap 进程通信
1. mmap 函数声明及头文件包含
man 2 mmap#include<sys/mman.h>
/* 创建映射区 */
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
/* 释放映射区 */
int munmap(void *addr, size_t length);
1.1 参数说明
参数:
- addr:指定映射区的首地址。通常传NULL,表示让系统自动分配
- length:共享映射区的大小(<= 文件实际大小)
- prot:共享内存区的读写属性
PROT_READ
PROT_WRITE
PROT_READ | PROT_WRITE- flag:标注共享内存的共享属性
MAP_SHARED(对内存的修改会反映到磁盘上)
MAP_PRIVATE(对内存的修改不会反映到磁盘上)- fd:用于创建共享内存映射区的那个文件的 文件描述符
- offset:从文件偏移位置开始建立映射区 (必须是4k的整数倍4096)默认0,表示映射文件全部
mmap返回值:
- 成功—映射区的首地址
- 失败—MAP_FAILED( 实质(void*)-1 ),设置errno
!!!!!mmap 极易容易出错,切记一定要检查mmap的返回值!!!!!!
munmap返回值:
- 成功— 0
- 失败— -1,设置errno
1.2 mmap 通信demo
- open 创建一个文件,并用 lseek 或者 ftruncate 拓展文件大小
- mmap创建映射区
- 往映射区写
- 读映射区
- 释放映射区
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/mman.h>
#include<fcntl.h>void sys_error(const char * str)
{perror(str);exit(1);
}int main(int argc, char * argv [])
{int fd, ret;char* p = NULL;fd = open("testmap", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd < 0){sys_error("open error\n");}/*lseek(fd, 10 , SEEK_END); // 与 ftruncate 等效write(fd, "\0", 1);*/ftruncate(fd, 10); // 需要写权限才能拓展文件大小int len = lseek(fd, 0, SEEK_END);p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED) // 返回值一定要检查{sys_error("mmap error\n");}strcpy(p, "hello mmap");printf("------%s\n, p");ret = munmap(p, len);if (ret == -1)sys_error("munmap error\n");close(fd);return 0;}
有一个创建的 testmap 文件!并实现内存映射
2. mmap 注意事项:
- 用于创建映射区的文件大小为0,实际指定非0大小创建映射区,出“总线错误”
- 用于创建映射区的文件大小为0,实际制定0大小创建映射区,出“无效参数”
- 用于创建映射区的文件读写属性为 只读。映射区属性为 读|写, 出“无效参数”
- 创建映射区,需要read权限。(创建映射区的过程中,隐含着一次对映射文件的读操作)当访问权限指定为 MAP_SHARED 时mmap的读写权限,应该 <= 文件open权限。 只写不行
- 文件描述符fd,在mmap创建映射区完成即可关闭。后续访问文件,用 地址 访问
- offset必须是4096的整数倍。(MMU 映射的最小单位是 4k)
- 对申请的映射区内存,不能越界访问
- munmap 用于释放的地址,必须是mmap申请返回的地址,对申请的映射区地址做操作赋值之前应该备份一份地址用作munmap
- 映射区访问权限为“私有”MAP_PRIVATE,对内存所做的所有修改,只在内存有效,不会反映到物理磁盘上。
- 映射区访问权限为“私有”MAP_PRIVATE,只需要open文件有读权限,就可用于创建映射区。因为私有不反应到物理磁盘上面,没有写的过程
2.1 mmap 函数的保险使用方法:
1. fd = open("文件名", O_RDWR)
2. p = mmap(NULL,有效文件大小, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
3. close(fd)
4. munmap(p, length)
3. demo 父子进程间mmap通信
父子等有血缘关系的进程之间也可以通过 mmap 建立的映射区来完成数据通信。但相应的要在创建映射区的时候指定对应的标志位参数 flags:
- MAP_SHARED(共享映射): 父子进程共享映射区
- MAP_PRIVATE(私有映射):父子进程各自独占映射区(各自读各自的)
- open创建文件,ftruncate 拓展文件大小
- mmap 建立映射区
- close 关闭文件
- fork 创建子进程
- 对映射区进程写读操作(写读操作有先后顺序 靠sleep实现)
- 回收映射区
/* 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 = 100;int main(void)
{int *p;int fd;pid_t pid;fd = open("temp", O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd < 0){perror("open error\n");exit(1);}ftruncate(fd, 4);p = (int*)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED){perror("mmap error\n");exit(1);}close(fd);pid = fork();if (pid == 0){*p = 7000; // 对映射区空间进行写操作var = 1000;printf("child, *p = %d, var = %d\n", *p, var);}else if(pid >0){sleep(1);printf("parent, *p = %d, var = %d\n", *p, var);wait(NULL);int ret = munmap(p,4);if (ret == -1){perror("munmap error\n");exit(1);}}return 0;
}
4. demo 非血缘关系进程间mmap通信
memcpy 函数:
memcpy --copy memory area------------
#include<string.h>void* memcpy(void* dest, void* src, size_t n);
---------------
写进程
- open创建文件,ftruncate 拓展文件大小
- mmap 创建映射区
- close关闭文件
- 往映射区内进行写操作
- 回收映射区
/* mmap_w.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/mman.h>void sys_error(const char * str)
{perror(str);exit(1);
}struct student{int id;char name[256];int age;
};int main(int argc, char * argv [ ])
{struct student stu = {0, "xiaoming", 18};struct student* p;int fd;fd = open("mmap_test", O_RDWR | O_CREAT |O_TRUNC, 0664);if (fd == -1)sys_error("open error\n");ftruncate(fd, sizeof(stu));p = (struct student*)mmap(NULL, sizeof(stu), PROT_READ |PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_error("mmap error\n");close(fd);while(1){memcpy(p, &stu, sizeof(stu));stu.id++;sleep(1);}int ret = munmap(p, sizeof(stu));if (ret == -1){sys_error("munmap error\n");}return 0;}
读进程
- open打开写进程创建的文件
- mmap 建立映射区
- close关文件
- 读映射区内容
- 回收映射区
/* mmap_r.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/mman.h>void sys_error(const char * str)
{perror(str);exit(1);
}struct student{int id;char name[256];int age;
};int main(int argc, char * argv [])
{struct student stu;struct student* p;int fd;fd = open("mmap_test", O_RDONLY);if (fd == -1)sys_error("open error\n");p = (struct student*)mmap(NULL, sizeof(stu), PROT_READ , MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_error("mmap error\n");close(fd);while(1){printf("id = %d, name = %s, age = %d\n",p->id,p->name, p->age);sleep(1);}int ret = munmap(p, sizeof(stu));if (ret == -1){sys_error("munmap error\n");}}
编译、运行:
5. mmap通信与fifo和文件通信的差异
mmap 同 fifo 区别:
- mmap:数据可以反复读取
- fifo:数据只能一次读取
mmap 同 文件 区别:
- mmap:映射到内存上,可以直接对内容进行指针操作
- 文件:open、close 打开关闭文件,read、write 来实现文件通信
6. 匿名映射(只能用于血缘关系进程间通信)
通常为了创建映射区要 open 一个 temp 文件,创建好了在 close 掉,比较麻烦。在父子进程通信中,可以直接使用匿名映射来代替。Linux 借助 flags 位 MAP_ANONYMOUS 来实现。
p = (int*)mmap(NUll, 4, PROT_READ |PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,0)
PS:因为没有指定文件名,所以只限于有血缘关系进程间通讯
类似方法还有 /dev/zero
int fd = open("/dev/zero", O_RDWR);
011mmap进程通信相关推荐
- Linux进程通信中IPC对象——IPC_PRIVATE与ftok
在linux中,可以使用IPC对象来进行进程间通信.IPC对象存在于内核中,多进程可以操作同一个IPC对象.每个IPC对象都有一个唯一的编号,该编号是由系统分配的.那么不同的进程如何知道这个编号,进而 ...
- Linux下进程通信知识点学习笔记(一)
4种主要事件导致进程创建: 系统的初始化: 执行了正在运行的进程所调用的进程创建系统调用: 用户请求创建一个进程: 一个批处理作业的初始化: 进程的终止: 正常退出: 出错退: 严重错误: 被其他进程 ...
- 跨进程通信,到底用长连接还是短连接
一个完整的软件系统大多数情况下是由多个进程共同协作进行的,哪怕它们在同一台服务器上.所以,进程之间如何进行高效的通信至关重要. 单个应用程序+单个数据库这套基础开发套餐我相信每个人都经历过,甚至在初期 ...
- linux一个进程通知另外一个进程,Linux进程通信学习笔记
一.为什么需要进程通信 1)数据传输 一个进程需要把它的数据发送给另一个进程. 2)资源共享 多个进程之间共享同样的资源. 3)通知事件 一个进程向另外一个进程发送消息,通知它发生了某事件. 4)进程 ...
- 大话android 进程通信之AIDL
上一篇的service涉及到进程通信问题,主要解决办法是通过 messenger来发送消息,这也是Google推荐的进程通信方式,比较简单易懂嘛~~,messenger底层也是通过binder来实现的 ...
- Binder跨进程通信原理(三):Binder IPC实现原理
1. 动态内核可加载模块 && 内存映射 正如上一章所说, 跨进程通信是需要内核空间做支持的. 传统的 IPC 机制如 管道, Socket, 都是内核的一部分, 因此通过内核支持来实 ...
- Binder跨进程通信原理(一):动态内核加载模块
先上一张Binder 的工作流程图.(如果不清晰,可以 复制图片链接到浏览器 或 保存到本地 查看,我经常都是这样看图的哈) 一开始上手,陌生的东西比较多,But,其实并不复杂.喔,流程图是用 Pro ...
- Android中的跨进程通信方法实例及特点分析(二):ContentProvider
1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据,Android系统给我们提供了Content P ...
- 【Binder 机制】进程通信 | 用户空间与内核空间 | MMU 与虚拟内存地址
文章目录 一.进程通信 二.用户空间与内核空间 三.MMU 与虚拟内存地址 一.进程通信 进程隔离概念 : 系统中的进程存在 " 进程隔离 " , 出于对进程运行的保护 , 两个进 ...
最新文章
- 曾在字节实习的程序员小姐姐,教你一步提取动漫线稿!比用PS更清晰
- 算法训练 区间k大数查询
- Ubuntu-16.04 部署 OpenStack Ocata下
- (转)CentOS 7系统详细开机启动流程和关机流程
- kappa一致性检验教程_SPSS在线_SPSSAU_Kappa一致性检验
- 点融产品 VP 赵征宇:增长是一个探索人性的过程
- 动态规划原理介绍(附7个算例,有代码讲解)
- 谷粒商城---新增收货地址,设置默认地址实现
- linux应用程序逆向,Linux下查看并下载命令源码包(根据命令/应用程序逆向获取并且安装其所属源码包)...
- Multi-Architecture镜像制作指南已到,请查收!
- oracle数据库扩容方案_ORACLE数据库扩容
- oracle+st_geometry
- Maven学习总结(26)——maven update时,报:Preference node org.eclipse.wst.validation...
- 【Vue2.0】— 消息订阅与发布pubsub(二十)
- 功能安全 李艳文_李艳文:智能网联全新安全问题凸显 相关自动驾驶事故逐年增加...
- Delphi之TStrings和TStringLists类[转]
- AppBox v6.0中实现子页面和父页面的复杂交互
- Python爬取 201865 条《隐秘的角落》弹幕,发现看剧不如爬山?
- 锐捷交换机密码恢复操作
- MySQL备份文件.ibd、.frm、.MYD、.MYI的恢复教程
热门文章
- 线上展厅生产车间vr搭建 广州商迪
- Linux使用iPhone USB共享网络
- c++语言随机数函数,C/C++产生随机数函数简单介绍
- 124、基于51单片机的智能电表功率电量仿真系统设计
- python 气泡图 聚类_10大Plotly数据可视化美图及工具介绍
- 前端面试题汇总大全 -- 持续更新!
- 蓝桥杯——第八届省赛_基于单片机的电子钟程序设计与调试
- java implements关键字_Java implements 关键字(keyword)
- JS鼠标事件onMouseOver和onMouseOut的坑
- ipguard,IM文件传送策略