1. 程式人生 > >linux網路程式設計之POSIX 共享記憶體和 系列函式

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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#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;
}
[email protected]:~/Documents/code/linux_programming/UNP/posix$ ./shm_open 
size=36, mode=664
[email protected]:~/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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#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;
}
[email protected]:~/Documents/code/linux_programming/UNP/posix$ ./shm_write 
size=36, mode=664
[email protected]:~/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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#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;
}
[email protected]:~/Documents/code/linux_programming/UNP/posix$ ./shm_read 
size=36, mode=664
name=test age=20

即讀取到了共享記憶體的資料,注意,讀取資料後共享記憶體的資料還是存在的,除非被覆蓋了。

參考:《UNP》

相關推薦

linux網路程式設計POSIX 共享記憶體 系列函式

在前面介紹了system v 共享記憶體的相關知識,現在來稍微看看posix 共享記憶體 和系列函式。 共享記憶體簡單來說就是一塊真正的實體記憶體區域,可以使用一些函式將這塊區域對映到程序的地址空間進行讀寫,而posix 共享記憶體與system v 共享記憶體不同的是它是

linux網路程式設計POSIX 訊息佇列 系列函式

#include<stdio.h>#include<stdlib.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>#include<unistd.h>#includ

linux網路程式設計POSIX訊息佇列

POSIX IPC名字限定: 必須以/打頭,並且後續不能有其它/ ,形如/somename 長度不能超過NAME_MAX 通過下面的命令將訊息佇列掛載到/dev/mqueue下,可通過cat/dev/mqueue/name檢視訊息佇列狀態 mount -t mqueue

linux網路程式設計posix 執行緒(四):posix 條件變數與互斥鎖 示例生產者--消費者問題

#include <unistd.h>#include <sys/types.h>#include <pthread.h>#include <semaphore.h>#include <stdlib.h>#include <stdio.h>

linux網路程式設計用socket實現簡單客戶端服務端的通訊(基於TCP)

一、介紹基於TCP協議通過socket實現網路程式設計常用API 1、讀者如果不是很熟悉,可以先看我之前寫的幾篇部落格,有socket,地址結構的理解,更加方便讀者理解 地址分別是: 2、socket(TCP)程式設計API簡介 1)、socket int s

linux網路程式設計用socket實現簡單客戶端服務端的通訊(基於UDP)

1、sendto和recvfrom函式介紹 sendto(經socket傳送資料) 相關函式 send , sendmsg,recv , recvfrom , socket 表頭檔案 #include < sys/types.h >#includ

Linux程序間通訊POSIX共享記憶體

共享記憶體是最高效的IPC機制,因為它不涉及程序之間的任何資料傳輸。這種高效率帶來的問題是,我們必須用其他輔助手段來同步程序對共享記憶體的訪問,否則會產生競態條件。因此,共享記憶體通常和其他程序間通訊方式一起使用。 Linux下有三種共享記憶體的IPC技術:S

linux網路程式設計TCP/IP基礎(二):利用ARPICMP協議解釋ping命令

一、MTU 乙太網和IEEE 802.3對資料幀的長度都有限制,其最大值分別是1500和1492位元組,將這個限制稱作最大傳輸單元(MTU,Maximum Transmission Unit)。如果I

linux網路程式設計socket(十六):通過UNIX域套接字傳遞描述符 sendmsg/recvmsg 函式

void send_fd(int sock_fd, int send_fd) {     int ret;     struct msghdr msg;     struct cmsghdr *p_cmsg;     struct iovec vec;     char cmsgbuf[CMSG_SPACE(

linux 網路程式設計廣播

linux 網路程式設計之廣播 轉載:https://blog.csdn.net/qdlovecsj/article/details/8805483 廣播方式主要是指使用UDP套介面傳送資料,傳送資料的目標地址不是普通的地址,而是所指定網路的廣播地址。 什麼是廣播地址?是指IP地

Linux網路程式設計TCP程式設計

直接上程式碼如下所示: 1、標頭檔案定義 #ifndef __HEAD_NET_H__ #define __HEAD_NET_H__ #include <stdio.h> #include <string.h> #include <stdlib.h>

Linux網路程式設計IO模型

本文基於IO訪問中存在的兩個階段詳細介紹了Linux產生的五種IO模型。 上篇文章回顧: 小米開源監控Open-Falcon收錄汽車之家貢獻的Win版Agent 同步與非同步 同步是指一個任務的完成需要依賴另外一個任務時,只有等待被依賴的任務完成後

linux網路程式設計多程序併發伺服器

1)使用多程序併發伺服器考慮的因素:       (1)父程序描述最大檔案描述符的個數(父程序需要關閉accept返回的新檔案描述符)       (2)系統內可建立程序的個數(與記憶體大小相關)       (3)程序建立過多是否降低整體服務效能 2)多程序建立併發

linux網路程式設計TCP狀態轉換及埠複用

(1)TCP狀態轉換圖               其中圖中分為三種狀態:實線代表的主動發起連線,虛線代表的被動發起連線,細實線代表的可以雙向發起連線的狀態。 主動發起連線方狀態變化:1)主動發起連線的一方傳送SYN標誌位,進入SYN_SENT狀態,等待接收被髮起連線方

Linux網路程式設計高階併發伺服器(轉)

1. 介紹 在上一節,我們介紹了Linux簡單的併發伺服器,通過在伺服器端建立多個子程序,來接收客戶端的請求,實現併發處理,但這種方式明顯有缺陷,伺服器並不知道客戶端請求的數量,所以事先建立的程序數不好確定。所以,這裡介紹三種高階併發伺服器模式。第一種是伺服器端統一

linux網路程式設計TCP介面詳解

socket int socket(int domain, int type, intprotocol);     監聽套接字描述符由socket建立,隨後用作bind和listen的第一個引數。一個伺服器通常僅建立一個監聽套接字,他在該伺服器的生命週期內一直存在。 c

linux網路程式設計RTP協議

以下內容取自: 本機通訊:https://www.cnblogs.com/lidabo/p/4160138.html(RTP協議傳輸)https://www.cnblogs.com/lidabo/p/4160145.html(RTP協議傳輸) 非本機:http://velep.com/arc

Linux網路程式設計 大小端初探

    首先解釋一下大小端的概念。    大端(Big Endian),同時也是網路序,是資料在網路上傳輸的一種資料組織格式,其儲存的方式比較符合人們讀寫的習慣。    小端(Little Endian

linux網路程式設計伺服器

基於tcp協議的網路程式 1.所用函式: socket函式 socket()開啟一個網路埠,如果成功,就像open()一樣返回一個檔案描述符,應用程式可以像讀寫檔案一樣用read/write在網路上首發資料,如果調用出錯返回-1 bind函式:

Android 網路程式設計同步,非同步,阻塞非阻塞

同步:函式沒有執行完不返回,執行緒被掛起;   阻塞:沒有收完資料函式不返回,執行緒也被掛起;  非同步:函式立即返回,通過事件或是訊號通知呼叫者;  非阻塞:函式立即返回,通過select通知呼叫者  同步:函式沒有執行完不返回,執行緒被掛起 阻塞:沒有收完資料函式不返回,執行緒也被掛起 非同步:函