linux网络编程之POSIX 共享内存和 系列函数

前面介绍了system v 共享内存的相关知识,现在来稍微看看posix 共享内存 和系列函数。

共享内存简单来说就是一块真正的物理内存区域,可以使用一些函数将这块区域映射到进程的地址空间进行读写,而posix 共享内存与system v 共享内存不同的是它是用虚拟文件系统(tmpfs)实现的,已经挂载在/dev/shm 下面。man 7 shm_overview

下面来看系列函数,编译时候加上 -lrt 选项,即连接librt 库 (实时库)

功能:用来创建或打开一个共享内存对象 原型 int shm_open(const char *name, int oflag, mode_t mode);  参数 name:共享内存对象的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255) oflag:与open函数类似,可以是O_RDONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_TRUNC等。 mode:此参数总是需要设置,如果oflag没有指定了O_CREAT,可以指定为0 返回值:成功返回非负整数文件描述符;失败返回-1

注意,不存在所谓的shm_close 函数,可以直接使用close 来关闭文件描述符。

功能:修改共享内存对象大小,shm_open不像shmget一样可以设置共享内存的大小,但可以使用ftruncate 设置大小。 原型 int ftruncate(int fd, off_t length); 参数 fd: 文件描述符 length:长度 返回值:成功返回0;失败返回-1

功能:获取共享内存对象信息 原型 int fstat(int fd, struct stat *buf); 参数 fd: 文件描述符 buf:返回共享内存状态 返回值:成功返回0;失败返回-1

struct stat 可以参考这里

类似 shmctl(, IPC_STAT,);

功能:删除一个共享内存对象 原型 int shm_unlink(const char *name);  参数 name: 共享内存对象的名字 返回值:成功返回0;失败返回-1

shm_unlink 类似 shmctl(, IPC_RMID, );

功能:将共享内存对象映射到进程地址空间。 原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); 参数 addr: 要映射的起始地址,通常指定为NULL,让内核自动选择 len:映射到进程地址空间的字节数 prot:映射区保护方式 flags:标志 fd:文件描述符 offset:从文件头开始的偏移量 返回值:成功返回映射到的内存区的起始地址;失败返回-1

前面曾经介绍了mmap 函数 将文件映射到进程地址空间的作用,其实它还可以将共享内存对象映射到进程地址空间,类似shmat的作用,只是传入的文件描述符fd 是shm_open 返回的。同样地,解除映射可以用munmap,类似shmdt 的作用。

下面写几个程序来演示一下:

shm_open.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666);
    if (shmid == -1)
        ERR_EXIT("shm_open");
    if (ftruncate(shmid, 36) == -1)
        ERR_EXIT("ftruncate");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_open 

size=36, mode=664

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ls -l /dev/shm/xyz 

-rw-rw-r-- 1 simba simba 36 Jun 16 15:01 /dev/shm/xyz

即创建了一个36字节的共享内存段,在/dev/shm 目录下。

shm_write.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDWR, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

    STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");

    strcpy(p->name, "test");
    p->age = 20;

    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_write 

size=36, mode=664

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ od -c /dev/shm/xyz 

0000000   t   e   s   t  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0

0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0

0000040 024  \0  \0  \0

0000044

使用mmap 将共享内存映射到进程地址空间,将shmid 传入fd 参数,其余跟文件映射没什么区别,od -c查看可以看到写入的东西。

shm_read.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDONLY, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

    STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");


    printf("name=%s age=%d\n", p->name, p->age);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_read 

size=36, mode=664

name=test age=20

即读取到了共享内存的数据,注意,读取数据后共享内存的数据还是存在的,除非被覆盖了。

参考:《UNP》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏漏斗社区

歪?我想要一个XXE。

0x00 背景 近期看到OWASP TOP 10 2017 版中添加了XXE的内容便对XXE的一些知识进行梳理和总结,XXE可以使用例如http,file等协...

3509
来自专栏浪淘沙

Hive学习

         Hive是基于Hadoop的一个数据仓库工具(离线),可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。

802
来自专栏我是攻城师

ElasticSearch2.1的java api批量建索引方法

2707
来自专栏大内老A

Enterprise Library深入解析与灵活应用(5):创建一个简易版的批处理执行器,认识Enterprise Library典型的配置方式和对象创建方式

最近负责一个框架性项目的升级,主要是从.NET Framework 3.0建议到.NET .NET Framework 3.5,开发工具也从VS2005迁移到V...

19310
来自专栏Porschev[钟慰]的专栏

Nodejs学习笔记(十四)— Mongoose介绍和入门

简介   Mongoose是在node.js异步环境下对mongodb进行便捷操作的对象模型工具   那么要使用它,首先你得装上node.js和mongodb,...

3666
来自专栏顶级程序员

让人疑惑的代码,竟成大多公司面试题热门!

? 小编今天给大家看的这个笔试题 当年可是火遍大江南北 不妨你先看看到底会不会 这是关于一段令人疑惑的Java代码 真题在此,谁敢不服 ▼ ? 你觉得简单,那...

3326
来自专栏CDA数据分析师

Python 异常处理完整指南

年前我写了一篇文章 Python classic, static, class and abstract methods,现在似乎到了更新的时候,今天我想来剖析...

23010
来自专栏九彩拼盘的叨叨叨

JavaScript 严格模式介绍

如我们所知,JavaScript 是一门灵活的语言。其灵活性同样也带来了很多坑,当然也有一些是设计缺陷。比如

832
来自专栏13blog.site

Spring+SpringMVC+MyBatis+easyUI整合优化篇(四)单元测试实例

前言 前一篇文章《Spring+SpringMVC+MyBatis+easyUI整合优化篇(三)代码测试》讲了不为和不能两个状态,针对不为,只能自己调整心态了,...

2895
来自专栏java学习

关于Spring 和 Spring MVC的43个问题【问题汇总】

通过Spring提供的IoC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。

571

扫码关注云+社区