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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux 消息队列机制

發(fā)布時(shí)間:2023/11/30 linux 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 消息队列机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

現(xiàn)在我們來討論第三種也是最后一種System V IPV工具:消息隊(duì)列。在許多方面看來,消息隊(duì)列類似于有名管道,但是卻沒有與打開與關(guān)閉管道的復(fù)雜關(guān)聯(lián)。然而,使用消息隊(duì)列并沒有解決我們使用有名管道所遇到的問題,例如管道上的阻塞。

?

消息隊(duì)列提供了一種在兩個(gè)不相關(guān)的進(jìn)程之間傳遞數(shù)據(jù)的簡(jiǎn)單高效的方法。與有名管道比較起來,消息隊(duì)列的優(yōu)點(diǎn)在獨(dú)立于發(fā)送與接收進(jìn)程,這減少了在打開與關(guān)閉有名管道之間同步的困難。

?

消息隊(duì)列提供了一種由一個(gè)進(jìn)程向另一個(gè)進(jìn)程發(fā)送塊數(shù)據(jù)的方法。另外,每一個(gè)數(shù)據(jù)塊被看作有一個(gè)類型,而接收進(jìn)程可以獨(dú)立接收具有不同類型的數(shù)據(jù)塊。消息隊(duì)列的好處在于我們幾乎可以完全避免同步問題,并且可以通過發(fā)送消息屏蔽有名管道的問題。更好的是,我們可以使用某些緊急方式發(fā)送消息。壞處在于,與管道類似,在每一個(gè)數(shù)據(jù)塊上有一個(gè)最大尺寸限制,同時(shí)在系統(tǒng)中所有消息隊(duì)列上的塊尺寸上也有一個(gè)最大尺寸限制。

?

盡管有這些限制,但是X/Open規(guī)范并沒有定義這些限制的具體值,除了指出超過這些尺寸是某些消息隊(duì)列功能失敗的原因。Linux系統(tǒng)有兩個(gè)定義,MSGMAXMSGMNB,這分別定義單個(gè)消息與一個(gè)隊(duì)列的最大尺寸。這些宏定義在其他系統(tǒng)上也許并不相同,甚至也許就不存在。

?

消息隊(duì)列函數(shù)定義如下:

?

#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

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);

?

與信息號(hào)和共享內(nèi)存一樣,頭文件sys/types.hsys/ipc.h通常也是需要的。

?

msgget

?

我們可以使用msgget函數(shù)創(chuàng)建與訪問一個(gè)消息隊(duì)列:

?

int msgget(key_t key, int msgflg);

?

與其他IPC工具類似,程序必須提供一個(gè)指定一個(gè)特定消息隊(duì)列的key值。特殊值IPC_PRIVATE創(chuàng)建一個(gè)私有隊(duì)列,這在理論上只可以為當(dāng)前進(jìn)程所訪問。與信息量和共享內(nèi)存一樣,在某些Linux系統(tǒng)上,消息隊(duì)列并不是私有的。因?yàn)樗接嘘?duì)列用處較少,因而這并不是一個(gè)嚴(yán)重問題。與前面一樣,第二個(gè)參數(shù),msgflg,由9個(gè)權(quán)限標(biāo)記組成。要?jiǎng)?chuàng)建一個(gè)新的消息隊(duì)列,由IPC_CREAT特殊位必須與其他的權(quán)限位進(jìn)行或操作。設(shè)置IPC_CREAT標(biāo)記與指定一個(gè)已存在的消息隊(duì)列并不是錯(cuò)誤。如果消息隊(duì)列已經(jīng)存在,IPC_CREAT標(biāo)記只是簡(jiǎn)單的被忽略。

?

如果成功,msgget函數(shù)會(huì)返回一個(gè)正數(shù)作為隊(duì)列標(biāo)識(shí)符,如果失敗則會(huì)返回-1

?

msgsnd

?

msgsnd函數(shù)允許我們將消息添加到消息隊(duì)列:

?

int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);

?

消息結(jié)構(gòu)由兩種方式來限定。第一,他必須小于系統(tǒng)限制,第二,必須以long int開始,這在接收函數(shù)中會(huì)用作一個(gè)消息類型。當(dāng)我們?cè)谑褂孟r(shí),最好是以如下形式來定義我們的消息結(jié)構(gòu):

?

struct my_message {

????long int message_type;

????/* The data you wish to transfer */

}

?

因?yàn)?/span>message_type用于消息接收,所以我們不能簡(jiǎn)單的忽略他。我們必須定義我們自己的數(shù)據(jù)結(jié)構(gòu)來包含并對(duì)其進(jìn)行初始化,從而他可以包含一個(gè)可知的值。

?

第一個(gè)參數(shù),msgid,是由msgget函數(shù)所返回的消息隊(duì)列標(biāo)識(shí)符。

?

第二個(gè)參數(shù),msg_ptr,是一個(gè)指向要發(fā)送消息的指針,正如前面所描述的,這個(gè)消息必須以long int類型開始。

?

第三個(gè)參數(shù),msg_sz,是由msg_ptr所指向的消息的尺寸。這個(gè)尺寸必須不包含long int消息類型。

?

第四個(gè)參數(shù),msgflg,控制如果當(dāng)前消息隊(duì)列已滿或是達(dá)到了隊(duì)列消息的系統(tǒng)限制時(shí)如何處理。如果msgflg標(biāo)記設(shè)置了IPC_NOWAIT,函數(shù)就會(huì)立即返回而不發(fā)送消息,并且返回值為-1。如果msgflg標(biāo)記清除了IPC_NOWAIT標(biāo)記,發(fā)送進(jìn)程就會(huì)被掛起,等待隊(duì)列中有可用的空間。

?

如果成功,函數(shù)會(huì)返回0,如果失敗,則會(huì)返回-1。如果調(diào)用成功,系統(tǒng)就會(huì)復(fù)制一份消息數(shù)據(jù)并將其放入消息隊(duì)列中。

?

msgrcv

?

msgrcv函數(shù)由一個(gè)消息隊(duì)列中收取消息:

?

int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);

?

第一個(gè)參數(shù),msqid,是由msgget函數(shù)所返回的消息隊(duì)列標(biāo)記符。

?

第二個(gè)參數(shù),msg_ptr,是一個(gè)指向?qū)⒁邮障⒌闹羔?#xff0c;正如在msgsnd函數(shù)中所描述的,這個(gè)消息必須以long int類型開始。

?

第三個(gè)參數(shù),msg_sz,是由msg_ptr所指向的消息的尺寸,并不包含long int消息類型。

?

第四個(gè)參數(shù),msgtype,是一個(gè)long int類型,允許一個(gè)接收優(yōu)先級(jí)形式的實(shí)現(xiàn)。如果msgtype的值為0,隊(duì)列中第一個(gè)可用的消息就會(huì)被接收。如果其值大于0,具有相同消息類型的第一個(gè)消息就會(huì)被接收。如果其值小于0,第一個(gè)具有相同類型或是小于msgtype絕對(duì)值的消息就會(huì)被接收。

?

這聽起來要比實(shí)際操作復(fù)雜得多。如果我們只是簡(jiǎn)單的希望以其發(fā)送的順序來接收消息,我們可以將msgtype設(shè)置為0。如果我們希望接收特殊消息類型的消息,我們可以將msgtype設(shè)置為等于這個(gè)值。如果我們希望接收消息類型為n或是小于n的值,我們可以將msgtype設(shè)置為-n

?

第五個(gè)參數(shù),msgflg,控制當(dāng)沒有合適類型的消息正在等待被接收時(shí)如何處理。如果在msgflg中設(shè)置了IPC_NOWAIT位,調(diào)用就會(huì)立即返回,而返回值為-1。如果msgflg標(biāo)記中消除了IPC_NOWAIT位,進(jìn)程就會(huì)被掛起,等待一個(gè)合適類型的消息到來。

?

如果成功,msgrcv會(huì)返回放入接收緩沖區(qū)中的字節(jié)數(shù),消息會(huì)被拷貝到由msg_ptr所指向的用戶分配緩沖區(qū)中,而數(shù)據(jù)就會(huì)由消息隊(duì)列中刪除。如果失敗則會(huì)返回-1

?

msgctl

?

最后一個(gè)消息隊(duì)列函數(shù)是msgctl,這與共享內(nèi)存中的控制函數(shù)十分類似。

?

int msgctl(int msqid, int command, struct msqid_ds *buf);

?

msqid_ds結(jié)構(gòu)至少包含下列成員:

?

struct msqid_ds {

????uid_t msg_perm.uid;

????uid_t msg_perm.gid

????mode_t msg_perm.mode;

}

?

第一個(gè)參數(shù),msqid,是由msgget函數(shù)所返回的標(biāo)記符。

?

第二個(gè)參數(shù),command,是要執(zhí)行的動(dòng)作。他可以取下面三個(gè)值:

?

命令 ???????描述

IPC_STAT ???設(shè)置msqid_ds結(jié)構(gòu)中的數(shù)據(jù)來反射與消息隊(duì)列相關(guān)聯(lián)的值。

IPC_SET ???????如果進(jìn)程有權(quán)限這樣做,這個(gè)命令會(huì)設(shè)置與msqid_ds數(shù)據(jù)結(jié)構(gòu)中所提供的消息隊(duì)列相關(guān)聯(lián)的值。

IPC_RMID ???刪除消息隊(duì)列。

?

如果成功則會(huì)返回0,如果失敗則會(huì)返回-1。當(dāng)進(jìn)程正在msgsnd或是msgrcv函數(shù)中等待時(shí)如果消息隊(duì)列被刪除,發(fā)送或接收函數(shù)就會(huì)失敗。

?

試驗(yàn)--消息隊(duì)列

?

現(xiàn)在我們已經(jīng)了解了消息隊(duì)列的定義,我們可以來看一下他們是如何實(shí)際工作的。與前面一樣,我們將會(huì)編寫兩個(gè)程序:msg1.c來接收,msg2.c來發(fā)送。我們會(huì)允許任意一個(gè)程序創(chuàng)建消息隊(duì)列,但是使用接收者在接收到最后一條消息后刪除消息隊(duì)列。

?

1 下面是接收程序:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

?

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

?

struct my_msg_st

{

????long int my_msg_type;

????char some_text[BUFSIZ];

};

?

int main()

{

????int running = 1;

????int msgid;

????struct my_msg_st some_data;

????long int msg_to_receive = 0;

?

2 首先,我們?cè)O(shè)置消息隊(duì)列:

?

????msgid = msgget((key_t)1234,0666|IPC_CREAT);

?

????if(msgid == -1)

????{

????????fprintf(stderr,"msgget failed with error: %d\n", errno);

????????exit(EXIT_FAILURE);

????}

?

3 然后,接收消息隊(duì)列中的消息直到遇到一個(gè)end消息。最后,消息隊(duì)列被刪除:

?

????while(running)

????{

????????if(msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1)

????????{

????????????fprintf(stderr, "msgrcv failed with errno: %d\n", errno);

????????????exit(EXIT_FAILURE);

????????}

?

????????printf("You wrote: %s", some_data.some_text);

????????if(strncmp(some_data.some_text, "end", 3)==0)

????????{

????????????running = 0;

????????}

????}

?

????if(msgctl(msgid, IPC_RMID, 0)==-1)

????{

????????fprintf(stderr, "msgctl(IPC_RMID) failed\n");

????????exit(EXIT_FAILURE);

????}

?

????exit(EXIT_SUCCESS);

}

?

4 發(fā)送程序與msg1.c類似。在main函數(shù)中,刪除msg_to_receive聲明,代之以buffer[BUFSIZ]。移除消息隊(duì)列刪除代碼,并且在running循環(huán)中做出如下更改。現(xiàn)在我們調(diào)用msgsnd來將輸入的文本發(fā)送到隊(duì)列中。

?

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <errno.h>

?

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

?

#define MAX_TEXT 512

?

struct my_msg_st

{

????long int my_msg_type;

????char some_text[MAX_TEXT];

};

?

int main()

{

????int running = 1;

????struct my_msg_st some_data;

????int msgid;

????char buffer[BUFSIZ];

?

????msgid = msgget((key_t)1234, 0666|IPC_CREAT);

?

????if(msgid==-1)

????{

????????fprintf(stderr,"msgget failed with errno: %d\n", errno);

????????exit(EXIT_FAILURE);

????}

?

????while(running)

????{

????????printf("Enter some text: ");

????????fgets(buffer, BUFSIZ, stdin);

????????some_data.my_msg_type = 1;

????????strcpy(some_data.some_text, buffer);

?

????????if(msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0)==-1)

????????{

????????????fprintf(stderr, "msgsnd failed\n");

????????????exit(EXIT_FAILURE);

????????}

?

????????if(strncmp(buffer, "end", 3) == 0)

????????{

????????????running = 0;

????????}

????}

?

????exit(EXIT_SUCCESS);

}

?

與管道中的例子不同,進(jìn)程并沒有必要提供自己的同步機(jī)制。這是消息隊(duì)列比起管道的一個(gè)巨大優(yōu)點(diǎn)。

?

假設(shè)消息隊(duì)列有空間,發(fā)送者可以創(chuàng)建隊(duì)列,在隊(duì)列中放入一些數(shù)據(jù),并且甚至可以在接收者啟動(dòng)之前退出。我們會(huì)首先運(yùn)行發(fā)送者。如下面的例子輸出:

?

$ ./msg2

Enter some text: hello

Enter some text: How are you today?

Enter some text: end

$ ./msg1

You wrote: hello

You wrote: How are you today?

You wrote: end

$

?

工作原理

?

發(fā)送者程序使用msgget創(chuàng)建一個(gè)消息隊(duì)列;然后使用msgsnd函數(shù)向隊(duì)列中添加消息。接收者使用msgget來獲得消息隊(duì)列標(biāo)識(shí)符,并且接收消息,直到接收到特殊消息end。然后他會(huì)使用msgctl刪除消息隊(duì)列進(jìn)行一些清理工作。

總結(jié)

以上是生活随笔為你收集整理的linux 消息队列机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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