1. 程式人生 > >day_13_管道、共享記憶體、訊息佇列

day_13_管道、共享記憶體、訊息佇列

一、使用管道實現程序間的通訊

1.1 基本概念

  管道本質上還是以檔案作為媒介,只是該檔案比較特殊,叫做管道檔案而已;
  管道主要分為兩大類:有名管道 和 無名管道;
    有名管道 - - - - - - 可以用於任意兩個程序間的通訊
    無名管道 - - - - - - 主要用於父子程序之間的通訊

1.2 使用有名管道實現程序間的通訊

  $ mkfifo xxx.pipe:表示建立管道檔案
如:
  $ touch a.txt      => 建立普通檔案a.txt,ls -l該檔案的型別是-
  $ echo hello > a.txt

  => 表示寫入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)程序間的通訊