day_13_管道、共享記憶體、訊息佇列
一、使用管道實現程序間的通訊
1.1 基本概念
管道本質上還是以檔案作為媒介,只是該檔案比較特殊,叫做管道檔案而已;
管道主要分為兩大類:有名管道 和 無名管道;
有名管道 - - - - - - 可以用於任意兩個程序間的通訊
無名管道 - - - - - - 主要用於父子程序之間的通訊
1.2 使用有名管道實現程序間的通訊
$ mkfifo xxx.pipe
:表示建立管道檔案
如:
$ touch a.txt
=> 建立普通檔案a.txt,ls -l該檔案的型別是-
$ echo hello > a.txt
$ cat a.txt
=> 表示檢視檔案a.txt中的內容,可以看到寫入的hello $ mkfifo a.pipe
=> 建立管道檔案a.pipe,ls -l該檔案的型別是p $ echo hello > a.pipe
=>表示寫入hello到檔案a.pipe中,不可以寫入,大小不變 另起一個終端,執行命令:
$ cat a.pipe
=> 表示讀取檔案a.pipe中的內容,可以看到hello => 但是檔案本身的大小還是不變;
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode); //mode_t = unsigned int;
- 功能:
- 主要用於建立引數指定的有名管道檔案;
- 引數:
- 第一個引數:字串形式的路徑名;
第二個引數:具體的許可權資訊,如:0664;
1.3 使用無名管道實現程序間的通訊
#include <unistd.h>
int pipe(int pipefd[2]);
- 功能:
- 主要用於建立一個無名管道,是一個單向的資料通道,可以實現兩個程序之間的通訊;
通過引數陣列可以返回兩個檔案描述符,其中pipefd[0]代表管道的讀端,pipefd[1]代表管道的寫端; - 注意:
- 管道檔案的特殊性就在於僅僅作為兩個程序間通訊的媒介,但是該檔案本身並不會儲存任何資料內容;
二、使用共享記憶體實現程序間的通訊
2.1 基本概念
共享記憶體本質上就是一塊由系統核心維護的記憶體空間,該記憶體空間被共享在兩個程序之間,從而通過讀寫實現通訊;
2.2 通訊模型
(1)獲取key值,使用ftok();
(2)建立 / 獲取共享記憶體,使用shmget();
(3)掛接共享記憶體,使用shmat();
(4)訪問共享記憶體;
(5)脫接共享記憶體,使用shmdt();
(6)如果不再使用,則刪除共享記憶體,使用shmctl();
2.3 相關函式的解析
(1)ftok()
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id); //key_t = int;
- 功能:
- 主要用於根據路徑名和專案的編號來生成key值;
- 引數:
- 第一個引數:字串形式的路徑名;(要求檔案必須存在,並且可以訪問)
第二個引數:專案的編號;(要求必須是非0,取低八位二進位制位) - 返回值:
- success —- key_t型別的key值,error —- -1;
- 注意:
- 使用相同的檔案路徑和相同的專案編號時,生成的key值也相同;
(2)shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
- 功能:
- 主要用於建立 / 獲取一個共享記憶體段;
- 引數:
- 第一個引數:key值,ftok()的返回值;
第二個引數:共享記憶體的大小;
0 - - - - - - - - - - - - - - - 獲取已經存在的共享記憶體
第三個引數:具體的操作標誌;
IPC_CREAT - - - - - - 若存在則建立,存在則開啟
IPC_EXCL - - - - - - - 與IPC_CREAT搭配使用,若存在則建立失敗
0 - - - - - - - - - - - - - - -獲取已經存在的共享記憶體 - 返回值:
- success —- 共享記憶體的ID,error —- -1;
- 注意:
- 當建立新的共享記憶體時,需要在第三個引數中通過按位或的方式來指定許可權資訊,如:0664;
(3)shmat()
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
- 功能:
- 主要用於掛接共享記憶體到當前程序的地址空間中;
- 引數:
- 第一個引數:共享記憶體的ID,shmget()的返回值;
第二個引數:共享記憶體的起始地址,給NULL由系統選擇;
第三個引數:具體的操作標誌,預設給0即可; - 返回值:
- success —- 共享記憶體段的掛接地址,error —- (void*)-1;
(4)shmdt()
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
- 功能:
- 主要用於脫接引數指定的掛接地址,引數一般傳遞shmat()的返回值;
(5)shmctl()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 功能:
- 主要用於對指定的共享記憶體執行指定的操作;
- 引數:
- 第一個引數:共享記憶體的ID,shmget()的返回值;
第二個引數:具體的操作命令;
IPC_RMID - - - - - 刪除共享記憶體,此時第三個引數給NULL即可
第三個引數:結構體指標
2.4 常見的基本命令
$ ipcs -m
- - - - - - - - - - - - - - - - - 表示檢視系統中已經存在的共享記憶體
$ ipcrm -m 共享記憶體的ID
- - - – 表示刪除指定的共享記憶體
三、使用訊息佇列實現程序間的通訊
3.1 基本概念
一般來說,首先將傳遞的資料打包成訊息,然後使用兩個程序分別傳送訊息到訊息佇列中 / 接收訊息佇列中的訊息,從而實現程序間的通訊;
3.2 通訊模型
(1)獲取key值,使用ftok();
(2)建立 / 獲取訊息佇列,使用msgget();
(3)傳送訊息到訊息佇列 / 接收訊息佇列中的訊息,使用msgsnd() / msgrcv();
(4)如果不再使用,則刪除訊息佇列,使用msgctl();
3.3 相關函式的解析
(1)msgget()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
- 功能:
- 主要用於建立 / 獲取一個訊息佇列;
- 引數:
- 第一個引數:key值,ftok()的返回值;
第二個引數:具體的操作標誌;
IPC_CREAT - - - - - - 若不存在則建立,存在則開啟;
IPC_EXCL - - - - - - - 與IPC_CREAT搭配使用,若存在則建立失敗
0 - - - - - - - - - - - - - – 獲取已經存在的訊息佇列 - 返回值:
- success —- 訊息佇列的ID,error —- -1;
- 注意:
- 當建立新的訊息佇列時,在第二個引數中需要通過按位或的方式來指定許可權資訊,如:0664;
(2)msgsnd()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 功能:
- 主要用於將指定的訊息傳送到指定的訊息佇列中;
- 引數:
- 第一個引數:訊息佇列的ID,msgget()的返回值;
第二個引數:訊息的首地址,訊息的一般格式如下:
struct msgbuf
{
long mtype; /* 訊息的型別,必須大於0 */
char mtext[1]; /* 訊息的內容,可以是其他型別 */
};
第三個引數:訊息的大小;(用於指定訊息內容的大小,不包括訊息的型別)
第四個引數:傳送的標誌,預設給0即可;
(3)msgrcv()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
/* ssize_t = long int; size_t = long unsigned int */
- 功能:
- 主要用於從指定的訊息佇列中接收指定的訊息;
- 引數:
- 第一個引數:訊息佇列的ID,msgget()的返回值;
第二個引數:存放資訊的首地址;
第三個引數:訊息的大小;(用於指定訊息內容的大小,不包括訊息的型別)
第四個引數:訊息的型別;
0 - - - - - - - 表示始終讀取訊息佇列中的第一個訊息
>0 - - - - - - 表示始終讀取訊息佇列中第一個型別為msgtyp的訊息
<0 - - - - - - 表示讀取訊息佇列中小於等於msgtyp絕對值的訊息,其中最小的型別優先讀取
第五個引數:具體的接收方式,預設給0即可; - 返回值:
- success —- 實際讀取的位元組數,error —- -1;
(4)msgctl()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 功能:
- 主要用於刪除訊息佇列;
- 引數:
- 第一個引數:訊息佇列的ID;
第二個引數:具體的操作命令;
IPC_RMID - - - - - - - - 刪除訊息佇列,此時第三個引數給NULL即可
第三個引數:結構體指標;
3.4 常見的基本命令
$ ipcs -q
- - - - - - - - - - - - - - - - - 表示檢視系統中已經存在的訊息佇列
$ ipcrm -q 訊息佇列的ID
- - - – 表示刪除指定的訊息佇列
- 明日預報:
- (1)程序間的通訊