前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux网络编程之POSIX 共享内存和 系列函数

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

作者头像
s1mba
发布2017-12-28 17:14:24
1.7K0
发布2017-12-28 17:14:24
举报
文章被收录于专栏:开发与安全开发与安全

前面介绍了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

代码语言:cpp
复制
#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

代码语言:cpp
复制
#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

代码语言:cpp
复制
#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》

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013-06-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档