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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux进程间通讯之消息队列

發布時間:2024/9/30 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux进程间通讯之消息队列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先有個大體的概念:http://www.xefan.com/archives/83703.html

頭文件: #include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

函數: key_t ftok(const char *filename, int proj_id);
通過文件名和項目號獲得System V IPC鍵值(用于創建消息隊列、共享內存所用)
proj_id:項目號,不為0即可
返回:成功則返回鍵值,失敗則返回-1

函數: int msgget(key_t key, int msgflg);
key:鍵值,當為IPC_PRIVATE時新建一塊共享內存;
shmflg:標志。
IPC_CREAT:內存不存在則新建,否則打開;
IPC_EXCL:只有在內存不存在時才創建,否則出錯。
返回:成功則返回標識符,出錯返回-1

函數: int msgsnd(int msgid, const void *msgp, size_t sz, int flg);
向消息隊列發送消息
msgid:通過msgget獲取
msgp:指向消息內容的指針
sz:消息內容的大小
flg:處理方式;如為IPC_NOWAIT時表示空間不足時不會阻塞
返回:成功則返回0,失敗返回-1

函數: int msgrcv(int msgid, void *msgp, size_t sz, long type, int flg);
從消息隊列讀取消息
msgid:通過msgget獲取
msgp:指向消息內容的指針
sz:消息內容的大小
type:指定接收的消息類型;若為0則隊列第一條消息將被讀取,而不管類型;若大于0則隊列中同類型的消息將被讀取,如在flg中設了MSG_RXCEPT位將讀取指定類型的其他消息;若小于0讀取絕對值小于type的消息。
flg:處理方式;
返回:成功返回收到消息長度,錯誤返回-1

函數: int msgctl(int msgid, int cmd, struct msgid_ds *buf);
msgid:通過msgget獲取
cmd:控制命令,如下:
IPC_STAT:獲取消息隊列狀態
IPC_SET:改變消息隊列狀態
IPC_RMID:刪除消息隊列
buf:結構體指針,用于存放消息隊列狀態
返回:成功返回與cmd相關的正數,錯誤返回-1

注意:消息隊列一旦創建就會一直存在系統中,直到手動刪除或者重啟系統??梢允褂胕pcs -q命令來查看系統存在的消息隊列。

/****************************************** 使用消息隊列進行進程通信——寫進程* 該進程用于創建信號量* 龍昌博客:http://www.xefan.com*****************************************/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h>typedef struct _msg_buf{long type; //消息類型char buf[100]; //消息內容 } msg_buf;int main() {int key, qid;msg_buf buf;key = ftok("tmp", 10);qid = msgget(key, IPC_CREAT);printf("key: %d\nqid: %d\n", key, qid);buf.type = 10;while (1){fgets(buf.buf, 100, stdin);if (msgsnd(qid, (void *)&buf, 100, 0) < 0){perror("msgsnd");exit(-1);}}return 0; }
/****************************************** 使用消息隊列進行進程通信——讀進程* 該進程用于創建信號量* 龍昌博客:http://www.xefan.com*****************************************/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h>typedef struct _msg_buf{long type; //消息類型char buf[100]; //消息內容 } msg_buf;int main() {int key, qid;msg_buf buf;key = ftok("tmp", 10);qid = msgget(key, IPC_CREAT);printf("key: %d\nqid: %d\n", key, qid);while (1){if (msgrcv(qid, (void *)&buf, 100, 0, 0) < 0){perror("msgrcv");exit(-1);}printf("type:%d\nget:%s\n", buf.type, buf.buf);}return 0; }
先運行寫進程再運行讀進程。



轉自:http://blog.csdn.net/liranke/article/details/5608686


很詳細


1.?基本概念

消息隊列的最佳定義是:內核地址空間中的內部鏈表。消息可以順序地發送到隊列中,

并以幾種不同的方式從隊列中獲取。當然,每個消息隊列都是由?IPC標識符所唯一標識的。

2.?內部和用戶數據結構

要完成理解象系統?V IPC這樣復雜的問題,關鍵是要徹底熟悉內核的幾個內部數據結構。

甚至對那些最基本的操作來說,直接訪問這些結構中的某幾個結構也是必要的,而其他的結

構則停留在一個更低的級別上。

3.?消息緩沖區

我們要介紹的第一個結構是?msgbuf結構。這個特殊的數據結構可以認為是消息數據的模

板。雖然定義這種類型的數據結構是程序員的職責,但是讀者絕對必須知道實際上存在

msgbuf類型的結構。它是在在?linux/msg.h中定義的,有2個成員:

? mtype它是消息類型,以正數來表示。這個數必須為一個正數!

? mtext它就是消息數據。

?

4.?內核msg結構

內核把消息隊列中的每個消息都存放在?msg結構的框架中。該結構是在?linux/msg.h中定義

的,如下是其成員的描述:

? msg_next這是一個指針,指向消息隊列中的下一個消息。在內核尋址空間中,它們

是當作一個鏈表存儲的。

? msg_type這是消息類型,它的值是在用戶結構?msgbuf中賦予的。

? msg_spot這是一個指針,指向消息體的開始處。

? msg_ts這是消息文本(消息體)的長度。

??內核?msgid_ds結構IPC對象分為三類,每一類都有一個內部數據結構,該數據結構

是由內核維護的。對于消息隊列而言,它的內部數據結構是???????????????msqid_ds結構。對于系統上

創建的每個消息隊列,內核均為其創建、存儲和維護該結構的一個實例。該結構在

linux/msg.h中定義,如下所示:

struct msqid_ds{

??? struct ipc_perm ??? msg_perm;??

??? msgqnum_t ? msg_qnum;??????

??? msglen_t??? msg_qbytes; ???

??? pid_t?????? msg_lspid;?????

??? pid_t ????? msg_lrpid;????? ???

??? time_t????? msg_stime;?????

??? time_t????? msg_rtime;?????

??? time_t????? msg_ctime;?????

??? ...

???

??? ...

};

?

?

?

在不同的系統中,此結構會有不同的新成員,這里只列出最少擁有的關鍵成員。其中,msg_qbytes成員以及msg_qnum成員在不同的系統也會有不同的上限值,這里就不逐一介紹了,詳細內容請參閱相關系統手冊。

? msg_perm它是?ipc_perm結構的一個實例,?ipc_perm結構是在?linux/ipc.h中定義的。

該成員存放的是消息隊列的許可權限信息,其中包括訪問許可信息,以及隊列的創建者

的有關信息?(uid等等)。

? msg_first鏈接到隊列中的第一個消息?(列表頭部?)。

? msg_last鏈接到隊列中的最后一個消息?(列表尾部)。

? msg_stime發送到隊列的最后一個消息的時間戳?(time_t)

? msg_rtime從隊列中獲取的最后一個消息的時間戳。

? msg_ctime對隊列進行最后一次變動的時間戳。

?

?

5.?內核ipc_perm結構

內核把IPC對象的許可權限信息存放在?ipc_perm類型的結構中。例如在前面描述的某個消

息隊列的內部結構中,?msg_perm成員就是?ipc_perm類型的,它的定義是在文件?linux/ipc.h中,

?

以上所有的成員都具有相當的自擴展性。對象的創建者以及所有者?(它們可能會有不同?)

有關信息,以及對象的?IPC關鍵字都是存放在該結構中的。八進制形式的訪問模式也是存放在

這里的,它是以一種無符號短整型的形式存儲的。最后,時間片使用序列編號存放在最后面,

每次通過系統調用關閉?IPC對象(摧毀)時,這個值將被增加一,至多可以增加到能駐留在系統

中的IPC對象的最大數目。用戶需要關心這個值嗎?答案是。

有關這個問題,在?Richard Stevens所著的《?Unix Network Programming?》一書的第125

中作了精辟的討論。該書還介紹了?ipc_perm結構的存在和行為在安全性方面的原因。

?

6.?創建消息隊列:

1?msgget簡介:為了創建一個新的消息隊列,或者訪問一個現有的隊列,可以使用系統調用?msgget ( )。


msgget ( )的第一個變元是關鍵字的值?(在我們的例子中該值是調用?ftok ( )的返回值)。這個

關鍵字的值將被拿來與內核中其他消息隊列的現有關鍵字值相比較。比較之后,打開或者訪

問操作依賴于msgflg變元的內容。

? IPC_CREAT如果在內核中不存在該隊列,則創建它。

? IPC_EXCL當與IPC_CREAT一起使用時,如果隊列早已存在則將出錯。

如果只使用了?IPC_CREAT, msgget ( )或者返回新創建消息隊列的消息隊列標識符,或者


會返回現有的具有同一個關鍵字值的隊列的標識符。如果同時使用了


I P C _ E X C L?IPC_CREAT,那么將可能會有兩個結果?;蛘邉摻ㄒ粋€新的隊列,或者如果該隊列存在,則

調用將出錯,并返回-1。IPC_EXCL本身是沒有什么用處的,但在與IPC_CREAT組合使用時,

它可以用于保證沒有一個現存的隊列為了訪問而被打開。

有個可選的八進制許可模式,它是與掩碼進行?OR操作以后得到的。這是因為從功能上講,

每個IPC對象的訪問許可權限與?Unix文件系統的文件許可權限是相似的!

?

2msgget舉例:

下面實例演示了使用msgget函數創建一個隊列,函數中參數falgs指定為IPC_CREAT|0666,說明新建一個權限為0666的消息隊列,其中組用戶、當前用戶以及其他用戶擁有讀寫的權限。并在程序的最后使用shell命令ipcs –q來查看系統IPC的狀態。

1)在vi編輯器中編輯該程序如下:

程序清單14-12? create_msg.c msgget函數

#include <sys/msg.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdio.h>

#include <stdlib.h>

int main ( void )

{

??? int???? qid;

??? key_t?????? key;

???

??? key = 113;

??? qid=msgget( key, IPC_CREAT | 0666 )?????? /*創建一個消息隊列*/

??? if ( qid < 0 ) {??????????????????????????? /*?創建一個消息隊列失敗?*/

??????? perror ( "msgget" );

??????? exit (1) ;

??? }

???

??? printf ("created queue id : %d /n", qid );? /*?輸出消息隊列的ID */

???

??? system( "ipcs -q" );??????????????????????? /*查看系統IPC的狀態*/

??? exit ( 0 );

}

2)在shell中編譯該程序如下:

$gcc create_msg.c–o create_msg

3)在shell中運行該程序如下:

$./ create_msg

created queue id : 0

------ Message Queues --------

key??????? msqid????? owner????? perms????? used-bytes?? messages

0x0000af40 623430?? root?? ??? 666??????? 0??????????? 0

0x0000007b 0????????? root?? ????666??????? 0??????????? 0

在程序中使用了系統命令ipcs,命令參數-q說明只查看消息隊列的狀態。注意在輸出消息中,key段標明的是IPCkey值,msqid為該隊列的ID值,perms為執行權限。同樣,隊列的執行權限像其他IPC對象一樣沒有執行權限。函數msgctl可以在隊列上做多種操作,函數原型如下:

#include <sys/msg.h>

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

參數msqid為指定的要操作的隊列,cmd參數指定所要進行的操作,其中有些操作需要buf參數。cmd參數的詳細取值及操作如表14-9所示。

14-9? cmd參數詳解

cmd

????

IPC_STAT

取隊列的msqid_ds結構,將它存放在buf所指向的結構中(需要buf參數)

IPC_SET

使用buf所指向結構中的值對當前隊列的相關結構成員賦值,其中包括:msg_perm.uid、msg_perm.gidmsg_perm.mode以及msg_perm.cuid。該命令只能由具有以下條件的進程執行:進程有效用戶ID等于msg_perm.cuidmsg_perm.uid超級用戶進程。其中只有超級用戶才可以增加隊列的msg_qbytes的值

IPC_RMID

刪除隊列,并清除隊列中的所有消息。此操作會影響后續進程對這個隊列的相關操作。該命令只能由具有以下條件的進程執行。進程有效用戶ID等于msg_perm.cuidmsg_perm.uid,超級用戶進程

下面實例演示了調用msgctl函數操作隊列,程序中先讀取命令行參數,如沒有,則打印命令提示信息,在調用msgctl函數執行刪除操作的前后分別調用了一次shell命令ipcs –q來查看系統IPC的狀態。

1)在vi編輯器中編輯該程序如下:

程序清單14-13? del_msg.c?調用msgctl刪除指定隊列

#include <sys/msg.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdio.h>

#include <stdlib.h>

int main ( int argc ,char *argv[] )

{

??? int qid ;

???

??? if ( argc != 2 ){ /*?命令行參數出錯?*/

??????? puts ( "USAGE: del_msgq.c <queue ID >" );

??????? exit ( 1 );

??? }

???

??? qid = atoi ( argv[1] ); /*?通過命令行參數得到組ID */

??? system( "ipcs -q");

???

??? if ( ( msgctl( qid, IPC_RMID, NULL ) ) < 0 ){ /*?刪除指定的消息隊列?*/

??????? perror ("msgctl");

??????? exit (1 );

??? }

??? system( "ipcs -q");

??? printf ( "successfully removed %d? queue/n", qid ); /*?刪除隊列成功?*/

??? exit( 0 );

}

2)在shell中編譯該程序如下:

$gcc del_msg.c–o del_msg

3)在shell中運行該程序如下:

$./ del_msg

------ Message Queues --------

key??????? msqid????? owner????? perms????? used-bytes?? messages???

0x0000007b 0????????? root?????? 666??????? 0??????????? 0??????????

------ Message Queues --------

key??????? msqid????? owner????? perms????? used-bytes?? messages???

successfully removed 0? queue ?

?

?

7.??讀寫消息隊列

一旦獲得了隊列標識符,用戶就可以開始在該消息隊列上執行相關操作了。為了向隊列

傳遞消息,用戶可以使用?msgsnd系統調用.

由于消息隊列的特殊性,系統為這個數據類型提供了兩個接口(msgsnd函數,msgrcv函數),分別對應寫消息隊列及讀消息隊列。將一個新的消息寫入隊列,使用函數msgsnd,函數原型如下:

#include <sys/msg.h>

int msgsnd ( int msqid, const void *prt, size_t nbytes, int flags);

對于寫入隊列的每一個消息,都含有三個值,正長整型的類型字段、數據長度字段和實際數據字節。新的消息總是放在隊列的尾部,函數中參數msqid指定要操作的隊列,ptr指針指向一個msgbuf的結構,定義如下:

struct msgbuf{

??? long mtype;

??? char mbuf[];

};

這是一個模板的消息結構,其中成員?mbuf是一個字符數組,長度是根據具體的消息來決定的,切忌消息不能以NULL結尾。成員mtype是消息的類型字段。

函數參數nbytes指定了消息的長度,參數flags指明函數的行為。函數成功返回0,失敗返回–1并設置錯誤變量errnoerrno可能出現的值有:EAGAINEACCES、EFAULT、EIDRMEINTREINVALENOMEM。當函數成功返回后會更新相應隊列的msqid_ds結構。

使用函數msgrcv可以從隊列中讀取消息,函數原型如下:

#include <sys/msg.h>

ssize_t msgrcv ( int msqid, void *ptr, size_t nbytes, long type , int flag);

函數中參數msqid為指定要讀的隊列,參數ptr為要接收數據的緩沖區,nbytes為要接收數據的長度,當隊列中滿足條件的消息長度大于nbytes的值時,則會參照行為參數flag的值決定如何操作:當flag中設置了MSG_NOERROR位時,則將消息截短到nbytes指定的長度后返回。如沒有MSG_NOERROR位,則函數出錯返回,并設置錯誤變量errno。設置type參數指定msgrcv函數所要讀取的消息,tyre的取值及相應操作如表14-10所示。

14-10? type值詳解

type

????

等于0

返回隊列最上面的消息(根據先進先出規則)

大于0

返回消息類型與type相等的第1條消息

小于0

返回消息類型小于等于type絕對值的最小值的第1條消息

參數flag定義函數的行為,如設置了IPC_NOWAIT位,則當隊列中無符合條件的消息時,函數出錯返回,errno的值為ENOMSG。如沒有設置IPC_NOWAIT位,則進程阻塞直到出現滿足條件的消息出現為止,然后函數讀取消息返回。

下面實例演示了消息隊列在進程間的通信。程序中創建了一個消息的模板結構體,并對聲明變量做初始化。使用msgget函數創建了一個消息隊列,使用msgsnd函數向該隊列中發送了一條消息。

1)在vi編輯器中編輯該程序如下:

程序清單14-14? snd_msg.c?調用msgsnd函數向隊列中發送消息

#include <sys/msg.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdio.h>

#include <stdlib.h>

struct msg{???????????????????? /*聲明消息結構體*/

??? long msg_types;???????????? /*消息類型成員*/???

??? char msg_buf[511];????????? /*消息*/

};

int main( void ) {

??? int???? qid;

??? int ??????? pid;

??? int ??? ??? len;

??? struct msg pmsg;??????????? /*一個消息的結構體變量*/

???

??? pmsg.msg_types = getpid();? /*消息類型為當前進程的ID*/

??? sprintf (pmsg.msg_buf,"hello!this is :%d/n/0", getpid() ); /*初始化消息*/

??? len = strlen ( pmsg.msg_buf );?? /*取得消息長度*/

???

??? if ( (qid=msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0 ) {? /*創建一個消
??? ??????????????????????????????????????????????????????????? ??
息隊列*/

??????? perror ( "msgget" );

??????? exit (1) ;

??? }

???

??? if ( (msgsnd(qid, &pmsg, len, 0 )) < 0 ){?? /*向消息隊列中發送消息*/

??????? perror ( "msgsn" );

??????? exit ( 1 );

??? }

??? printf ("successfully send a message to the queue: %d /n", qid);

??? exit ( 0 ) ;

}

2)在shell中編譯該程序如下:

$gcc snd_msg.c –o snd_msg

3)在shell中運行該程序如下:

$./ snd_msg

successfully send a message to the queue 0

上述程序中,先定義了一個消息的結構體。該結構體中包含兩個成員,long類型成員msg_types是消息的類型,注意,在消息隊列中是以消息類型做索引值來進行檢索的。char類型數組存放消息。在程序中先聲明了一個消息的結構體變量,并做相應初始化,然后使用了msgget函數創建一個消息隊列,并將該消息發送到此消息隊列中。以下是一個使用消息隊列發送消息的程序。

下面實例演示了如何使用隊列讀取消息。在程序的開始部分,判斷用戶是否輸入了目標消息隊列ID,如果沒有,則打印命令的幫助信息;如果用戶輸入了隊列的ID,則從隊列中取出該消息,并輸出到標準輸出。

1)在vi編輯器中編輯該程序。

程序清單14-15? rcv_msg.c?使用msgrcv函數從指定隊列中讀出消息

#include <sys/msg.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <stdio.h>

#include <stdlib.h>

#define BUFSZ 4096

struct msg{???????????? /*聲明消息結構體*/

??? long msg_types;???? /*消息類型成員*/???

??? char msg_buf[511];? /*消息*/

};

int main( int argc, char * argv[] ) {

??? int???? qid;

??? int ??????? len;

??? struct msg pmsg;

??? if ( argc != 2 ){? /**/

??????? perror ( "USAGE: read_msg <queue ID>" );

??????? exit ( 1 );

??? }

???

??? qid = atoi ( argv[1] );?? /*從命令行中獲得消息隊列的ID*/

??? /*從指定隊列讀取消息?*/

??? len = msgrcv ( qid, &pmsg, BUFSZ, 0, 0 );

???

??? if ( len > 0 ){

??????? pmsg.msg_buf[len] = '/0';?????????????????????? /*為消息添加結束符*/

??????? printf ("reading queue id :%05ld/n", qid ); /*輸出隊列ID*/

??????? /*該消息類型就是發送消息的進程ID*/

??????? printf ("message type : %05ld/n", pmsg.msg_types );

??????? printf ("message length : %d bytes/n", len );?? /*消息長度*/

??????? printf ("mesage text: %s/n", pmsg.msg_buf); /*消息內容*/

??? }

??? else if ( len == 0 )

??????? printf ("have no message from queue %d/n", qid );

??? else {

??????? perror ( "msgrcv");

??????? exit (1);

??? }

??? system("ipcs -q")??

??? exit ( 0 ) ;

}

2)在shell中編譯該程序如下:

$gcc rcv_msg.c–o rcv _msg

3)在shell中運行該程序如下:

$./ rcv_msg 0

reading queue id :0

message type : 03662

message length : 20 bytes

mesage text: hello!this is :3662

------ Message Queues --------

key??????? ??msqid????? owner????? perms????? used-bytes?? messages???

0x00000000 ?0????????? root?????? ?666??????? ?0??????????? 0??????????

該程序中聲明了一個消息的結構體類型變量,并從命令行中得到所要操作的消息隊列,然后使用函數msgrcv從指定消息隊列中讀取隊列中最上面的一條消息(函數的第4個參數等于0,說明根據先進先出規則,應從隊列的最上面讀取一條消息),并將該消息輸出到標準輸出。在發送消息的程序中,消息類型字段指定的是發送消息進程的ID,可以使用該內容來判斷信息的來源。



總結

以上是生活随笔為你收集整理的Linux进程间通讯之消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。