歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux管理 >> Linux網絡 >> linux網絡編程之POSIX共享內存和系列函數

linux網絡編程之POSIX共享內存和系列函數

日期:2017/3/3 16:26:17   编辑:Linux網絡

在前面介紹了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 可以參考這裡。

類似 shm_ctl(,IPC_STAT,);

功能:刪除一個共享內存對象

原型 int shm_unlink(const char *name);

參數

name: 共享內存對象的名字

返回值:成功返回0;失敗返回- 1

shm_unlink 類似 shm_ctl(,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

即讀取到了共享內存的數據,注意,讀取數據後共享內存的數據還是存在的,除非被覆蓋了。

Copyright © Linux教程網 All Rights Reserved