日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

【Linux系统编程】进程间通信之消息队列

發(fā)布時間:2024/4/24 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Linux系统编程】进程间通信之消息队列 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

00. 目錄

文章目錄

    • 00. 目錄
    • 01. 消息隊列概述
    • 02. 消息隊列相關(guān)函數(shù)
    • 03. 消息隊列讀寫操作
    • 04. 測試代碼
    • 05. 附錄

01. 消息隊列概述

消息隊列提供了一種在兩個不相關(guān)的進程之間傳遞數(shù)據(jù)的簡單高效的方法,其特點如下:

1)消息隊列可以實現(xiàn)消息的隨機查詢。消息不一定要以先進先出的次序讀取,編程時可以按消息的類型讀取。

2)消息隊列允許一個或多個進程向它寫入或者讀取消息。

3)與無名管道、命名管道一樣,從消息隊列中讀出消息,消息隊列中對應(yīng)的數(shù)據(jù)都會被刪除。

4)每個消息隊列都有消息隊列標(biāo)識符,消息隊列的標(biāo)識符在整個系統(tǒng)中是唯一的。

5)消息隊列是消息的鏈表,存放在內(nèi)存中,由內(nèi)核維護。只有內(nèi)核重啟或人工刪除消息隊列時,該消息隊列才會被刪除。若不人工刪除消息隊列,消息隊列會一直存在于系統(tǒng)中。

02. 消息隊列相關(guān)函數(shù)

消息隊列常用操作函數(shù)如下:

#include <sys/msg.h> #include <sys/types.h> #include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id); int msgget(key_t key, int msgflg); int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg); int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg); int msgctl(int msqid, int cmd, struct msqid_ds *buf);

對于消息隊列的操作,我們可以類比為這么一個過程:假如 A 有個東西要給 B,因為某些原因 A 不能當(dāng)面直接給 B,這時候他們需要借助第三方托管(如銀行),A 找到某個具體地址的建設(shè)銀行,然后把東西放到某個保險柜里(如 1 號保險柜),對于 B 而言,要想成功取出 A 的東西,必須保證去同一地址的同一間銀行取東西,而且只有 1 號保險柜的東西才是 A 給自己的。

對于上面的例子,涉及到幾個比較重要的信息:地址、銀行、保險柜號碼

只有同一個地址才能保證是同一個銀行,只有是同一個銀行雙方才能借助它來托管,只有同一個保險柜號碼才能保證是對方托管給自己的東西。

而在消息隊列操作中,鍵(key)值相當(dāng)于地址,消息隊列描述符相當(dāng)于具體的某個銀行,消息類型相當(dāng)于保險柜號碼。

同一個鍵(key)值可以保證是同一個消息隊列,同一個消息隊列描述符才能保證不同的進程可以相互通信,同一個消息類型才能保證某個進程取出是對方的信息。

鍵(key)值

System V 提供的進程間通信機制需要一個 key 值,通過 key 值就可在系統(tǒng)內(nèi)獲得一個唯一的消息隊列標(biāo)識符。key 值可以是人為指定的,也可以通過 ftok() 函數(shù)獲得。

#include <sys/types.h> #include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id); 功能:獲取鍵(key)值 參數(shù):pathname: 路徑名proj_id: 項目ID,非 0 整數(shù)(只有低 8 位有效) 返回值:成功:key 值失敗:-1

創(chuàng)建消息隊列函數(shù)

#include <sys/msg.h>int msgget(key_t key, int msgflg); 功能:創(chuàng)建一個新的或打開一個已經(jīng)存在的消息隊列。不同的進程調(diào)用此函數(shù),只要用相同的 key 值就能得到同一個消息隊列的標(biāo)識符。參數(shù):key: ftok() 返回的 key 值msgflg: 標(biāo)識函數(shù)的行為及消息隊列的權(quán)限,其取值如下:IPC_CREAT:創(chuàng)建消息隊列。IPC_EXCL: 檢測消息隊列是否存在。位或權(quán)限位:消息隊列位或權(quán)限位后可以設(shè)置消息隊列的訪問權(quán)限,格式和open() 函數(shù)的 mode_t一樣(open() 的使用請點此鏈接),但可執(zhí)行權(quán)限未使用。返回值:成功:消息隊列的標(biāo)識符失敗:-1

參考代碼如下:

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h>int main(int argc, char *argv[]) {key_t key;int msgqid;key = ftok(".", 2012); // key 值// 創(chuàng)建消息隊列msgqid = msgget(key, IPC_CREAT|0666);return 0; }

測試結(jié)果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out #查看消息隊列 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -q--------- 消息隊列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息 0xdc320009 0 deng 666 0 0 #刪除消息隊列 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcrm -q 0 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -q--------- 消息隊列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

03. 消息隊列讀寫操作

對于消息隊列的讀寫,都是以消息類型為準(zhǔn)。消息類型相當(dāng)于保險柜號碼,A 往 1 號保險柜放東西,對方想取出 A 的東西必須也是從 1 號保險柜里取。同理,某一進程往消息隊列添加 a 類型的消息,別的進程要想取出這進程添加的信息也必須取 a 類型的消息。

在學(xué)習(xí)消息隊列讀寫操作前,我們先學(xué)習(xí)消息隊列的消息格式:

typedef struct _msg {long mtype; // 消息類型char mtext[100]; // 消息正文//…… …… // 消息的正文可以有多個成員 }MSG;

消息類型必須是長整型的,而且必須是結(jié)構(gòu)體類型的第一個成員,類型下面是消息正文,正文可以有多個成員(正文成員可以是任意數(shù)據(jù)類型的)。至于這個結(jié)構(gòu)體類型叫什么名字,里面成員叫什么名字,自行定義,沒有明文規(guī)定

發(fā)送消息

#include <sys/msg.h>int msgsnd( int msqid, const void *msgp, size_t msgsz, int msgflg); 功能:將新消息添加到消息隊列。 參數(shù):msqid: 消息隊列的標(biāo)識符。msgp: 待發(fā)送消息結(jié)構(gòu)體的地址。msgsz: 消息正文的字節(jié)數(shù)。msgflg:函數(shù)的控制屬性,其取值如下:0msgsnd() 調(diào)用阻塞直到條件滿足為止。IPC_NOWAIT: 若消息沒有立即發(fā)送則調(diào)用該函數(shù)的進程會立即返回。 返回值:成功:0失敗:-1

接收消息

#include <sys/msg.h>ssize_t msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg ); 功能:從標(biāo)識符為 msqid 的消息隊列中接收一個消息。一旦接收消息成功,則消息在消息隊列中被刪除。 參數(shù):msqid:消息隊列的標(biāo)識符,代表要從哪個消息列中獲取消息。msgp: 存放消息結(jié)構(gòu)體的地址。msgsz:消息正文的字節(jié)數(shù)。msgtyp:消息的類型。可以有以下幾種類型:msgtyp = 0:返回隊列中的第一個消息。msgtyp > 0:返回隊列中消息類型為 msgtyp 的消息(常用)。msgtyp < 0:返回隊列中消息類型值小于或等于 msgtyp 絕對值的消息,如果這種消息有若干個,則取類型值最小的消息。注意:在獲取某類型消息的時候,若隊列中有多條此類型的消息,則獲取最先添加的消息,即先進先出原則。msgflg:函數(shù)的控制屬性。其取值如下:0msgrcv() 調(diào)用阻塞直到接收消息成功為止。MSG_NOERROR: 若返回的消息字節(jié)數(shù)比 nbytes 字節(jié)數(shù)多,則消息就會截短到 nbytes 字節(jié),且不通知消息發(fā)送進程。IPC_NOWAIT: 調(diào)用進程會立即返回。若沒有收到消息則立即返回 -1。 返回值:成功:讀取消息的長度失敗:-1

消息隊列控制

#include <sys/msg.h>int msgctl(int msqid, int cmd, struct msqid_ds *buf); 功能:對消息隊列進行各種控制,如修改消息隊列的屬性,或刪除消息消息隊列。 參數(shù):msqid:消息隊列的標(biāo)識符。cmd:函數(shù)功能的控制。其取值如下:IPC_RMID:刪除由 msqid 指示的消息隊列,將它從系統(tǒng)中刪除并破壞相關(guān)數(shù)據(jù)結(jié)構(gòu)。IPC_STAT:將 msqid 相關(guān)的數(shù)據(jù)結(jié)構(gòu)中各個元素的當(dāng)前值存入到由 buf 指向的結(jié)構(gòu)中。相對于,把消息隊列的屬性備份到 buf 里。IPC_SET:將 msqid 相關(guān)的數(shù)據(jù)結(jié)構(gòu)中的元素設(shè)置為由 buf 指向的結(jié)構(gòu)中的對應(yīng)值。相當(dāng)于,消息隊列原來的屬性值清空,再由 buf 來替換。buf:msqid_ds 數(shù)據(jù)類型的地址,用來存放或更改消息隊列的屬性。返回值:成功:0失敗:-1

04. 測試代碼

寫消息隊列代碼

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h>typedef struct _msg {long mtype;char mtext[50]; }MSG;int main(int argc, char *argv[]) {key_t key;int msgqid;MSG msg;key = ftok("./", 2015); // key 值// 創(chuàng)建消息隊列msgqid = msgget(key, IPC_CREAT|0666);if(msgqid == -1){perror("msgget");exit(-1);}msg.mtype = 10; // 消息類型strcpy(msg.mtext, "hello mike"); // 正文內(nèi)容/* 添加消息msg_id:消息隊列標(biāo)識符&msg:消息結(jié)構(gòu)體地址sizeof(msg)-sizeof(long):消息正文大小0:習(xí)慣用0*/msgsnd(msgqid, &msg, sizeof(msg)-sizeof(long), 0);return 0; }

讀消息隊列代碼

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h>typedef struct _msg {long mtype;char mtext[50]; }MSG;int main(int argc, char *argv[]) {key_t key;int msgqid;key = ftok("./", 2015); // key 值// 創(chuàng)建消息隊列msgqid = msgget(key, IPC_CREAT|0666);if(msgqid == -1){perror("msgget");exit(-1);}MSG msg;memset(&msg, 0, sizeof(msg));/* 取出類型為 10 的消息msg_id:消息隊列標(biāo)識符&msg:消息結(jié)構(gòu)體地址sizeof(msg)-sizeof(long):消息正文大小(long)10:消息的類型0:習(xí)慣用0*/msgrcv(msgqid, &msg, sizeof(msg)-sizeof(long), (long)10, 0);printf("msg.mtext=%s\n", msg.mtext); // 把消息隊列刪除// IPC_RMID:刪除標(biāo)志位msgctl(msgqid, IPC_RMID, NULL);return 0; }

寫端代碼測試:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -q--------- 消息隊列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息 0xdf320009 32768 deng 666 56 1 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

讀端代碼測試:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out msg.mtext=hello mike deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ipcs -q--------- 消息隊列 ----------- 鍵 msqid 擁有者 權(quán)限 已用字節(jié)數(shù) 消息 deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$

05. 附錄

總結(jié)

以上是生活随笔為你收集整理的【Linux系统编程】进程间通信之消息队列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。