一,管道PIPE

二,FIFO通信

三,mmap通信

创建内存映射区。

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int mmap(void *addr, size_t length);

函数mmap:打开一个文件,指定一个文件的区域,作为一个区域,映射到内存中,以后就直接操作那个内存,就能够实现进程间的通信。因为是内存操作,所以速度最快。

  • addr:固定NULL
  • length: 拿出文件中的多长的一段,映射到内存。
  • offset: 从文件内容中的哪个位置开始拿。
  • prot

PROT_EXEC Pages may be executed

PROT_READ Pages may be read.

PROT_WRITE Pages may be written

PROT_NONE Pages may not be accessed

  • flags

MAP_SHARED: 对内存里的值进行修改,会反映到文件,也就是文件也被修改。

MAP_PRIVATE:对内存里的值进行修改,不会反映到文件,文件不会被修改。

  • offset: 起始位置
  • 返回值:

成功:可用的内存的首地址

失败:MAP_FAILED(that is, (void *) -1)

释放内存映射区.

#include <sys/mman.h>
int munmap(void *addr, size_t length);
  • addr: mmap的返回值;
  • length: mmap创建的长度;
  • 返回值: 成功0, 失败-1.

例子:

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main() {int fd = open("mem", O_RDWR);// char *buf = mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);char *buf = mmap(NULL, 8, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);printf("%s\n", buf);strcpy(buf, "FFFFF");//释放映射区munmap(buf, 8);close(fd);
}

mmap的七个问题:

  • 如果更改上面例子里变量buf的地址,释放的时候munmap,还能成功吗?

不能成功,错误信息: [Invalid argument]

  • 对映射区的操作,越界了怎么样?

open文件size > 要写入的size > mmap参数的length: 能够全部写入文件。

open文件size < 要写入的size > mmap参数的length: 不能全部写入文件,能够给写入的size是open文件的size

  • 偏移量随便填个数字会怎么样?

mmap函数出错,错误信息: [Invalid argument]

offset必须是4K的整数倍,[0, 4*1024......]

用[stat]命令查看文件,发现文件的size实际小于4096,但是[IO Block: 4096]

File: pi2.c

Size: 442 Blocks: 8 IO Block: 4096 regular file

Device: 801h/2049d Inode: 424247 Links: 1

Access: (0664/-rw-rw-r--) Uid: ( 1000/ ys) Gid: ( 1000/ ys)

Access: 2019-05-02 12:54:13.812282158 +0800

Modify: 2019-04-29 13:49:42.489004001 +0800

Change: 2019-04-29 13:49:42.489004001 +0800

  • 如果文件描述符先关闭,对mmap映射有没有影响。

没有影响。

  • open的时候,可以用新创建一个文件的方式,来创建映射区吗?

错误:Bus error(core dumped).

错误理由是:创建的文件的size为0,所以出上面的错误。新创建一个文件后,马上把文件大小扩展一下就不会发生错误了。

int fd = open("mem", O_RDWR|O_CREAT, 0666);
ftruncate(fd, 8); //把新创建的文件mem的大小扩展为8.
  • open文件时,选择O_WRONLY,可以吗

mmap函数出错,错误: [Permission denied]。

因为要把文件的内容读到内存,所以隐含一次读取操作,所有没有读的权限的话,就出这个错误。

  • 当选择MAP_SHARED的时候,open文件选择O_RDONLY,prot可以选择[PROT_READ|PROT_WRITE]吗

mmap函数出错,错误: 【Permission denied】.

MAP_SHARED的时候会去写文件,但是open的时候只有读权限,所以权限不够。

用mmap实现父子进程间通信的例子:

注意:参数flags必须是MAP_SHARED,因为2个进程间通信,需要互相读写,所以必须是MAP_SHARED

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>int main() {int fd = open("mem", O_RDWR);int* mem = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mem == MAP_FAILED) {perror("mmap");return -1;}pid_t pid = fork();if (pid == 0) {*mem = 100;printf("child:mem=%d\n", *mem);sleep(3);printf("child:mem=%d\n", *mem);}else if (pid > 0) {sleep(1);printf("parent:mem=%d\n", *mem);*mem = 200;printf("parent:mem=%d\n", *mem);wait(NULL);}munmap(mem, 4);close(fd);
}

执行结果:

child:mem=100

parent:mem=100

parent:mem=200

child:mem=200

不知道读者同学们发现了没有,用mmap有个非常鸡肋的地方,就是必须要使用一个文件,其实这个文件对程序没有什么作用。所以linux给我们提供了一个方法,叫做[匿名映射]。

匿名映射:在调用mmap函数时候,在flags参数那里,设置[MAP_ANON],并在fd参数那里设置[-1]。

int* mem = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);

有个问题,在有些unix系统里是没有[MAP_ANON][MAP_ANONYMOUS]这2个宏的,这2个宏的作用是一样的,其中一个是简写。那怎么办呢?

使用下面2个文件去映射,因为要用文件,所以必须还得有open的调用,但好处是不用事先做出一个大小合适的文件了。

  • /dev/zero: 可以随意映射,size无限大,诨名为[聚宝盆]
  • /dev/null:可以随意映射,size无限大,但映射完后,文件里不会存有任何内容,所以也叫[无底洞],一般错误日志太多,而且不想保留的时候,会重定向到这个文件。

匿名映射的弱点:不能实现无血缘关系进程间的通信。

用mmap实现无血缘关系的进程间通信的例子:

写入端:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>typedef struct _student {int id;char name[20];
} Student;int main(int argc, char *argv[]) {int fd = open("aaa", O_RDWR|O_TRUNC|O_CREAT, 0666);int length = sizeof(Student);ftruncate(fd, length);Student *std = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (std == MAP_FAILED) {perror("mmap");return -1;}int num = 0;while (1) {std->id = num;sprintf(std->name, "xiaoming-%03d", num++);sleep(1);}munmap(std, length);close(fd);
}

读入端:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>typedef struct _student{int fd;char name[20];
} Student;int main(int argc, char *argv[]) {int fd = open("aaa", O_RDWR);int length = sizeof(Student);Student *std = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (std == MAP_FAILED) {perror("mmap");return -1;}while (1) {printf("id:%03d, name:%s\n", std->id, std->name);sleep(1);}munmap(std, length);close(fd);
}

利用mmap实现用多个进程拷贝一个文件的例子

核心思想:把要拷贝的文件和目标文件都映射成内存映射区,然后在各自的子进程里做拷贝,拷贝时,注意起点和大小。

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>//argv[1]: 进程的数量
//argv[2]: 要拷贝的文件
int main(int argc, char *argv[]) {if (argc < 3) {printf("bad argv, need 3 arg\n");return -1;}//用stat函数取得文件的大小struct stat sbuf;int ret = stat(argv[2], &sbuf);if (ret < 0) {perror("stat");return -1;}//文件的大小off_t sz = sbuf.st_size;//余数off_t yu = sz % atoi(argv[1]);//每个进程拷贝的大小off_t proSz = (sz - yu) / atoi(argv[1]);//open src fileint srcfd = open(argv[2], O_RDONLY);//create target filechar wk[20] = {0};sprintf(wk, "%s.copy", argv[2]);int decfd = open(wk, O_RDWR|O_CREAT|O_TRUNC, 0766);//创建和src文件同等大小的目标文件ret = ftruncate(decfd, sz);if (ret < 0) {perror("ftruncate");return -1;}//打开要被拷贝文件的内存映射区void *dst = mmap(NULL, sz, PROT_READ, MAP_SHARED, srcfd, 0);if (src == MAP_FAILED) {perror("mmap src:");return -1;}//打开要目标文件的内存映射区void *dst = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, decfd, 0);if (dst == MAP_FAILED) {perror("mmap dst:");return -1;}int i;int pCnt = atoi(argv[1]);//创建子进程,都是这些子进程都是本程序的子进程for (i=0; i<pCnt; ++i) {//in child processif (fork() == 0) {break;}}//子进程的处理if (i < pCnt) {//last timeif (i == pCnt - 1) {memcpy(dst+i*proSz, src+i*proSz, proSz+yu);}else {memcpy(dst+i*proSz, src+i*proSz, proSz);}}//父进程的处理else {for (int i=0; i<pCnt; ++i) {wait(NULL);}//printf("parent pid=%d\n", getpid());if (munmap(src, sz) == -1) {perror(munmap src");}if (munmap(dst, sz) == -1) {perror("munmap dsc");}close(srcfd);close(decfd);}}

linux 进程通信之 mmap相关推荐

  1. linux 进程通信子mmap

    mmap 文件–内存映射 函数原型 #include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int fla ...

  2. Linux进程通信之mmap

    mmap()函数: void *mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset); 返回:成功:返回创建的映射 ...

  3. Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结

    Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...

  4. linux进程管道通信缺点,Linux进程通信(IPC)的方式详解

    前言:Linux进程通信的方式 什么是进程通信?进程通信是指进程之间交换信息 进程通信方式共有6种: 管道(pipe),包括流管道(s_pipe)和有名管道(named pipe) 信号(signal ...

  5. Linux进程通信的试验

    1.实验目的 1.1了解Linux进程通信的概念. 1.2 掌握Linux进程通信的常用方法. 2.实验内容 创建admin用户,密码也是admin. 用admin登陆后,创建src目录,所有的源代码 ...

  6. Linux进程通信——匿名管道、命名管道、管道的特性和共享内存

    Linux进程通信--匿名管道.命名管道.管道的特性和共享内存 一.管道 1.1 什么是管道? 1.2 匿名管道 <1> 匿名管道参数说明 <2> fork共享管道原理 < ...

  7. 【操作系统实验】Linux进程通信—共享内存通信、管道通信

    Linux进程通信-共享内存通信.管道通信 一.实验目的: 二.实验题目: 1. 试设计程序利用共享内存完成如下进程通信 1.shmget函数 2.shmat函数 3.shmdt函数 4.shmctl ...

  8. linux进程通信发送方式,Linux服务器编程——Linux系统编程之进程通信

    进程通信又称IPC IPC方法 方法:管道(最简单) 信号(开销最小) 共享映射区/共享内存(无血缘关系) 本地套接字(最稳定) Linux文件类型: -   文件 d  目录 l   符号链接 s  ...

  9. 操作系统实验·Linux进程通信与内存管理

    预备知识 Linux进程的数据结构 在Linux中,进程用task_struct表示,所有进程被组织到以init_task为表头的双向链表中(见[include/linux/sched.h]SET_L ...

最新文章

  1. NotificationCenter
  2. 2.1 词汇表征-深度学习第五课《序列模型》-Stanford吴恩达教授
  3. Mybatis用#{}从传递过来的参数中取值
  4. CF 839 E-最大团
  5. 2018-2019-1 20165231 实验四 外设驱动程序设计
  6. 罗马音平假名片假名转换器_关于五十音你所要知道的一切!文末附日网高清字帖...
  7. 移动客户端UI设计指南
  8. gson 获取hasmap_GSON fromJson return LinkedHashMap instead of EnumMap
  9. Visio2013 64位下载安装以及破解激活教程
  10. GNS3新手安装教程
  11. 利用MapGis6.7 对 jpg图像文件进行图形校准
  12. 笨办法学Python习题11 提问
  13. 2020-2021 年度广东省职业院校学生专业技能大赛网络空间安全赛项竞赛规程
  14. 【LearnOpenGL】-PBR材质
  15. DSPE-PEG7-NHS ester分子式:C63H1117N2O20P琥珀酰亚胺PEG连接剂
  16. 《安富莱嵌入式周报》第209期:2021.04.19--2021.04.25
  17. 戴尔服务器720dx格式化硬盘,《图解戴尔iDRAC服务器远程控制设置》.docx
  18. 上传文件时,文件名中文乱码
  19. 在家也能查sci--漫游登陆web of science
  20. 企业各首席官以及工作介绍

热门文章

  1. read-only file system怎么改权限_“我就退出家长群!怎么了?”压垮成年人仅需一个“家长群”上热搜?...
  2. 使用SSH密钥对给你的阿里云ECS加把安全锁
  3. MySQL局域网内访问慢的原因及解决方法
  4. 洛谷——P1042 乒乓球
  5. 【简单易懂】getBean(id)和getBean(Class)使用的区别
  6. 13行代码AC_Justifying the Conjecture Gym - 102394J(解题报告)
  7. 天平应什么放置_天平是否应该放干燥剂?
  8. 申通快递机器人上岗_申通快速分拣机器人未来有70%人会失业
  9. mysql拒绝访问root用户_设置mysql的root用户允许远程登录
  10. android webview 获取网页内容,在WebView中获取网页中的内容