Linux處理序間通訊: 訊息佇列

來源:互聯網
上載者:User

    Linux的訊息佇列(queue)實質上是一個鏈表, 它有訊息佇列標識符(queue ID). msgget建立一個新隊列或開啟一個存在的隊列; msgsnd向隊列末端添加一條新訊息; msgrcv從隊列中取訊息, 取訊息是不一定遵循先進先出的, 也可以按訊息的類型欄位取訊息.

 

1. 標識符(des)和鍵(key):

    訊息佇列, 訊號量和共用儲存段, 都屬於核心中的IPC結構, 它們都用標識符來描述. 這個標識符是一個非負整數, 與檔案描述符不同的是, 建立時並不會重複利用通過刪除回收的整數, 而是每次+1, 直到整數最大值迴轉到0.

    標識符是IPC對象的內部名, 而它的外部名則是key(鍵), 它的基本類型是key_t, 在標頭檔<sys/types.h>中定義為長整型. 鍵由核心變換成標識符.

2. 訊息佇列狀態msqid_ds:

    每個訊息佇列都有一個msqid_ds結構與其關聯:

struct msqid_ds
...{
    struct ipc_perm msg_perm; /**//* access */
    msgqnum_t       msg_qnum; /**//* # of messages on queue */
    msglen_t           msg_qbytes; /**//* max # of bytes on queue */
    pid_t                 msg_lspid;  /**//* pid of last msgsnd() */
    pid_t                 msg_lrpid;  /**//* pid of last msgrcv() */
    time_t               msg_stime; /**//* last-msgsnd() time */
    time_t               msg_rtime; /**//* last-msgrcv() time */
    time_t               msg_ctime; /**//* last-change time */
    ...
    ...
    ...
};

 

3. 由路徑名和項目ID產生一個key:

    如果客戶進程和伺服器處理序認同一個路徑名和項目ID(0~255間的字元值), 接著調用ftok將這兩個值變換為一個key.

  • 原型: key_t ftok(const char *path, int id);
  • 標頭檔: <sys/ipc.h>
  • 傳回值: 成功則返回key, 出錯則返回(key_t)-1.
  • 參數: path參數必須引用一個現存檔案. 當產生key時 只使用id參數的低8位.
  • 說明: 如果兩個路徑名引用兩個不同的檔案, 對這兩個路徑名調用ftok通常返回不同的key. 但是, 因為i節點號和key通常存放在長整型中, 於是建立key時可能會丟失資訊. 這意味著, 如果使用同一項目ID, 那麼對於不同檔案的兩個路徑名可能產生相同的key. 該函數的工作方式為:
    • 按給定的路徑名取得其stat結構.
    • 從該結構中取出部分st_dev和st_ino欄位, 與項目ID組合起來.

4. 建立/開啟訊息佇列:

    msgget可以建立一個新隊列或開啟一個存在的隊列.

  • 原型: int msgget(key_t key, int flag);
  • 標頭檔: <sys/msg.h>
  • 傳回值: 成功則返回訊息佇列ID, 出錯則返回-1.
  • 參數:
    • key: 訊息佇列的key值.
    • flag: 標誌位.
  • 說明:
    • 建立隊列有兩種方法:
      • key是IPC_PRIVATE.
      • key當前未與特定類型的IPC結構相結合, 並且flag中指定了IPC_CREAT位.
    • 初始化msqid_ds成員:
      • ipc_perm中的mode成員按flag進行設定.
      • msg_qnum, msg_lspid, msg_lrpid, msg_stime和msg_rtime都設定為0.
      • msg_ctime設定為目前時間.
      • msg_qbytes設定為系統限制值.

5. 訊息佇列的垃圾桶函數:

    msgctl類似於驅動程式中的ioctl函數, 可對訊息佇列執行多種操作.

  • 原型: int msgctl(int msqid, int cmd, struct msgqid_ds *buf);
  • 標頭檔: <sys/msg.h>
  • 傳回值: 成功則返回0, 出錯則返回-1.
  • 參數: cmd參數說明對msqid指定的隊列要執行的命令:
    • IPC_STAT: 取此隊列的msqid_ds結構, 並將它存放在buf指向的結構中.
    • IPC_SET: 按由buf指向結構中的值, 設定與此隊列相關結構中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. 該命令只有下列兩種進程可以執行:
      • 有效使用者ID等於msg_perm.cuid或msg_per.uid.
      • 具有超級使用者特權的進程.
    • IPC_RMID: 從系統中刪除該訊息佇列以及仍在該隊列中的所有資料. 執行許可權同上.

6. 將資料放到訊息佇列:

    調用msgsnd將資料放到訊息佇列中.

  • 原型: int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
  • 標頭檔: <sys/msg.h>
  • 傳回值: 成功則返回0, 出錯則返回-1.
  • 說明: 可以定義一個訊息結構, 結構中帶類型, 這樣就可用非先進先出順序取訊息了. 當msgsnd成功返回, 與訊息佇列相關的msqid_ds結構得到更新, 以標明發出該調用的進程ID(msg_lsqid), 進行該調用的時間(msg_stime), 並指示隊列中增加了一條訊息(msg_qnum).

7. 從訊息佇列中取訊息:

    調用msgrcv將從訊息佇列中取訊息.

  • 原型: ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
  • 標頭檔: <sys/msg.h>
  • 傳回值: 成功則返回訊息的資料部分的長度, 出錯則返回-1.
  • 參數:
    • ptr: 指向一個長整型數(返回的訊息類型存放在其中), 跟隨其後的是存放實際訊息資料的緩衝區.
    • nbytes: 資料緩衝區的長度. 若返回的訊息大於nbytes, 且在flag中設定了MSG_NOERROR, 則該訊息被截短.
    • type:
      • type == 0: 返回隊列中的第一個訊息.
      • type > 0: 返回隊列中訊息類型為type的第一個訊息.
      • type < 0: 返回隊列中訊息類型值小於或等於type絕對值的訊息, 如果這種訊息有若干個, 則取類型值最小的訊息.
  • 說明: 當msgrcv成功返回時, 與訊息佇列相關的msqid_ds結構被更新, 以指示調用者的進程ID(msg_lrpid), 調用時間(msg_rtime)和隊列中的訊息數(msg_qnum)減1.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.