Linux環(huán)境進(jìn)程間通信三消息隊列_第1頁
Linux環(huán)境進(jìn)程間通信三消息隊列_第2頁
Linux環(huán)境進(jìn)程間通信三消息隊列_第3頁
Linux環(huán)境進(jìn)程間通信三消息隊列_第4頁
Linux環(huán)境進(jìn)程間通信三消息隊列_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、.Linux環(huán)境進(jìn)程間通信 三 消息隊列Linux環(huán)境進(jìn)程間通信三消息隊列2020年12月09日星期四14:42消息隊列也叫做報文隊列可以抑制早期unix通信機制的一些缺點。作為早期unix通信機制之一的信號可以傳送的信息量有限,后來雖然POSIX 1003.1 b在信號的實時性方面作了拓廣,使得信號在傳遞信息量方面有了相當(dāng)程度的改進(jìn),但是信號這種通信方式更像"即時"的通信方式,它要求承受信號的進(jìn)程在某個時間范圍內(nèi)對信號做出反響,因此該信號最多在承受信號進(jìn)程的生命周期內(nèi)才有意義,信號所傳遞的信息是接近于隨進(jìn)程持續(xù)的概念process-persistent,見附錄1;管道及有

2、名管道及有名管道那么是典型的隨進(jìn)程持續(xù)IPC,并且,只能傳送無格式的字節(jié)流無疑會給應(yīng)用程序開發(fā)帶來不便,另外,它的緩沖區(qū)大小也受到限制。消息隊列就是一個消息的鏈表??梢园严⒖醋饕粋€記錄,具有特定的格式以及特定的優(yōu)先級。對消息隊列有寫權(quán)限的進(jìn)程可以向中按照一定的規(guī)那么添加新消息;對消息隊列有讀權(quán)限的進(jìn)程那么可以從消息隊列中讀走消息。消息隊列是隨內(nèi)核持續(xù)的參見附錄1。目前主要有兩種類型的消息隊列:POSIX消息隊列以及系統(tǒng)V消息隊列,系統(tǒng)V消息隊列目前被大量使用??紤]到程序的可移植性,新開發(fā)的應(yīng)用程序應(yīng)盡量使用POSIX消息隊列。在本系列專題的序深化理解Linux進(jìn)程間通信IPC中,提到對于消息

3、隊列、信號燈、以及共享內(nèi)存區(qū)來說,有兩個實現(xiàn)版本:POSIX的以及系統(tǒng)V的。Linux內(nèi)核內(nèi)核2.4.18支持POSIX信號燈、POSIX共享內(nèi)存區(qū)以及POSIX消息隊列,但對于主流Linux發(fā)行版本之一redhad8.0內(nèi)核2.4.18,還沒有提供對POSIX進(jìn)程間通信API的支持,不過應(yīng)該只是時間上的事。因此,本文將主要介紹系統(tǒng)V消息隊列及其相應(yīng)API。在沒有聲明的情況下,以下討論中指的都是系統(tǒng)V消息隊列。系統(tǒng)V消息隊列是隨內(nèi)核持續(xù)的,只有在內(nèi)核重起或者顯示刪除一個消息隊列時,該消息隊列才會真正被刪除。因此系統(tǒng)中記錄消息隊列的數(shù)據(jù)構(gòu)造struct ipc_ids msg_ids位于內(nèi)核中,

4、系統(tǒng)中的所有消息隊列都可以在構(gòu)造msg_ids中找到訪問入口。消息隊列就是一個消息的鏈表。每個消息隊列都有一個隊列頭,用構(gòu)造struct msg_queue來描繪參見附錄2。隊列頭中包含了該消息隊列的大量信息,包括消息隊列鍵值、用戶ID、組ID、消息隊列中消息數(shù)目等等,甚至記錄了最近對消息隊列讀寫進(jìn)程的ID。讀者可以訪問這些信息,也可以設(shè)置其中的某些信息。以以下圖說明了內(nèi)核與消息隊列是怎樣建立起聯(lián)絡(luò)的:其中:struct ipc_ids msg_ids是內(nèi)核中記錄消息隊列的全局?jǐn)?shù)據(jù)構(gòu)造;struct msg_queue是每個消息隊列的隊列頭。從上圖可以看出,全局?jǐn)?shù)據(jù)構(gòu)造struct ipc_i

5、ds msg_ids可以訪問到每個消息隊列頭的第一個成員:struct kern_ipc_perm;而每個struct kern_ipc_perm可以與詳細(xì)的消息隊列對應(yīng)起來是因為在該構(gòu)造中,有一個key_t類型成員key,而key那么唯一確定一個消息隊列。kern_ipc_perm構(gòu)造如下:struct kern_ipc_perm/內(nèi)核中記錄消息隊列的全局?jǐn)?shù)據(jù)構(gòu)造msg_ids可以訪問到該構(gòu)造;key_t key;/該鍵值那么唯一對應(yīng)一個消息隊列uid_t uid;gid_t gid;uid_t cuid;gid_t cgid;mode_t mode;unsigned long seq;1、

6、翻開或創(chuàng)立消息隊列消息隊列的內(nèi)核持續(xù)性要求每個消息隊列都在系統(tǒng)范圍內(nèi)對應(yīng)唯一的鍵值,所以,要獲得一個消息隊列的描繪字,只需提供該消息隊列的鍵值即可;注:消息隊列描繪字是由在系統(tǒng)范圍內(nèi)唯一的鍵值生成的,而鍵值可以看作對應(yīng)系統(tǒng)內(nèi)的一條路經(jīng)。2、讀寫操作消息讀寫操作非常簡單,對開發(fā)人員來說,每個消息都類似如下的數(shù)據(jù)構(gòu)造:struct msgbuflong mtype;char mtext1;mtype成員代表消息類型,從消息隊列中讀取消息的一個重要根據(jù)就是消息的類型;mtext是消息內(nèi)容,當(dāng)然長度不一定為1。因此,對于發(fā)送消息來說,首先預(yù)置一個msgbuf緩沖區(qū)并寫入消息類型和內(nèi)容,調(diào)用相應(yīng)的發(fā)送函

7、數(shù)即可;對讀取消息來說,首先分配這樣一個msgbuf緩沖區(qū),然后把消息讀入該緩沖區(qū)即可。3、獲得或設(shè)置消息隊列屬性:消息隊列的信息根本上都保存在消息隊列頭中,因此,可以分配一個類似于消息隊列頭的構(gòu)造struct msqid_ds,見附錄2,來返回消息隊列的屬性;同樣可以設(shè)置該數(shù)據(jù)構(gòu)造。消息隊列API 1、文件名到鍵值#include sys/types.h#include sys/ipc.h key_t ftokchar*pathname,char proj;它返回與途徑pathname相對應(yīng)的一個鍵值。該函數(shù)不直接對消息隊列操作,但在調(diào)用ipcMSGGET,或msgget來獲得消息隊列描繪字

8、前,往往要調(diào)用該函數(shù)。典型的調(diào)用代碼是:key=ftokpath_ptr,'a';ipc_id=ipcMSGGET,intkey,flags,0,NULL,0;2、linux為操作系統(tǒng)V進(jìn)程間通信的三種方式消息隊列、信號燈、共享內(nèi)存區(qū)提供了一個統(tǒng)一的用戶界面:int ipcunsigned int call,int first,int second,int third,void*ptr,long fifth;第一個參數(shù)指明對IPC對象的操作方式,對消息隊列而言共有四種操作:MSGSND、MSGRCV、MSGGET以及MSGCTL,分別代表向消息隊列發(fā)送消息、從消息隊列讀取消息、

9、翻開或創(chuàng)立消息隊列、控制消息隊列;first參數(shù)代表唯一的IPC對象;下面將介紹四種操作。int ipcMSGGET,intfirst,intsecond,intthird,void*ptr,longfifth;與該操作對應(yīng)的系統(tǒng)V調(diào)用為:int msggetkey_tfirst,second。int ipcMSGCTL,intfirst,intsecond,intthird,void*ptr,longfifth與該操作對應(yīng)的系統(tǒng)V調(diào)用為:int msgctlfirst,second,struct msqid_ds*ptr。int ipcMSGSND,intfirst,intsecond,in

10、tthird,void*ptr,longfifth;與該操作對應(yīng)的系統(tǒng)V調(diào)用為:int msgsndfirst,struct msgbuf*ptr,second,third。int ipcMSGRCV,intfirst,intsecond,intthird,void*ptr,longfifth;與該操作對應(yīng)的系統(tǒng)V調(diào)用為:int msgrcvfirst,struct msgbuf*ptr,second,fifth,third,注:本人不主張采用系統(tǒng)調(diào)用ipc,而更傾向于采用系統(tǒng)V或者POSIX進(jìn)程間通信API。原因如下:雖然該系統(tǒng)調(diào)用提供了統(tǒng)一的用戶界面,但正是由于這個特性,它的參數(shù)幾乎不能給

11、出特定的實際意義如以first、second來命名參數(shù),在一定程度上造成開發(fā)不便。正如ipc手冊所說的:ipc是linux所特有的,編寫程序時應(yīng)注意程序的移植性問題;該系統(tǒng)調(diào)用的實現(xiàn)不過是把系統(tǒng)V IPC函數(shù)進(jìn)展了封裝,沒有任何效率上的優(yōu)勢;系統(tǒng)V在IPC方面的API數(shù)量不多,形式也較簡潔。3.系統(tǒng)V消息隊列API系統(tǒng)V消息隊列API共有四個,使用時需要包括幾個頭文件:#include sys/types.h#include sys/ipc.h#include sys/msg.h 1int msggetkey_t key,int msgflg參數(shù)key是一個鍵值,由ftok獲得;msgflg參

12、數(shù)是一些標(biāo)志位。該調(diào)用返回與健值key相對應(yīng)的消息隊列描繪字。在以下兩種情況下,該調(diào)用將創(chuàng)立一個新的消息隊列:假設(shè)沒有消息隊列與健值key相對應(yīng),并且msgflg中包含了IPC_CREAT標(biāo)志位;key參數(shù)為IPC_PRIVATE;參數(shù)msgflg可以為以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或結(jié)果。調(diào)用返回:成功返回消息隊列描繪字,否那么返回-1。注:參數(shù)key設(shè)置成常數(shù)IPC_PRIVATE并不意味著其他進(jìn)程不能訪問該消息隊列,只意味著即將創(chuàng)立新的消息隊列。2int msgrcvint msqid,struct msgbuf*msgp,int msgsz,l

13、ong msgtyp,int msgflg;該系統(tǒng)調(diào)用從msgid代表的消息隊列中讀取一個消息,并把消息存儲在msgp指向的msgbuf構(gòu)造中。msqid為消息隊列描繪字;消息返回后存儲在msgp指向的地址,msgsz指定msgbuf的mtext成員的長度即消息內(nèi)容的長度,msgtyp為懇求讀取的消息類型;讀消息標(biāo)志msgflg可以為以下幾個常值的或:IPC_NOWAIT假設(shè)沒有滿足條件的消息,調(diào)用立即返回,此時,errno=ENOMSG IPC_EXCEPT與msgtyp 0配合使用,返回隊列中第一個類型不為msgtyp的消息IPC_NOERROR假設(shè)隊列中滿足條件的消息內(nèi)容大于所懇求的ms

14、gsz字節(jié),那么把該消息截斷,截斷部分將喪失。msgrcv手冊中詳細(xì)給出了消息類型取不同值時0;0;=0,調(diào)用將返回消息隊列中的哪個消息。msgrcv解除阻塞的條件有三個:消息隊列中有了滿足條件的消息;msqid代表的消息隊列被刪除;調(diào)用msgrcv的進(jìn)程被信號中斷;調(diào)用返回:成功返回讀出消息的實際字節(jié)數(shù),否那么返回-1。3int msgsndint msqid,struct msgbuf*msgp,int msgsz,int msgflg;向msgid代表的消息隊列發(fā)送一個消息,即將發(fā)送的消息存儲在msgp指向的msgbuf構(gòu)造中,消息的大小由msgze指定。對發(fā)送消息來說,有意義的msgf

15、lg標(biāo)志為IPC_NOWAIT,指明在消息隊列沒有足夠空間包容要發(fā)送的消息時,msgsnd是否等待。造成msgsnd等待的條件有兩種:當(dāng)前消息的大小與當(dāng)前消息隊列中的字節(jié)數(shù)之和超過了消息隊列的總?cè)萘?;?dāng)前消息隊列的消息數(shù)單位"個"不小于消息隊列的總?cè)萘繂挝?quot;字節(jié)數(shù)",此時,雖然消息隊列中的消息數(shù)目很多,但根本上都只有一個字節(jié)。msgsnd解除阻塞的條件有三個:不滿足上述兩個條件,即消息隊列中有包容該消息的空間;msqid代表的消息隊列被刪除;調(diào)用msgsnd的進(jìn)程被信號中斷;調(diào)用返回:成功返回0,否那么返回-1。4int msgctlint msqid,

16、int cmd,struct msqid_ds*buf;該系統(tǒng)調(diào)用對由msqid標(biāo)識的消息隊列執(zhí)行cmd操作,共有三種cmd操作:IPC_STAT、IPC_SET、IPC_RMID。IPC_STAT:該命令用來獲取消息隊列信息,返回的信息存貯在buf指向的msqid構(gòu)造中;IPC_SET:該命令用來設(shè)置消息隊列的屬性,要設(shè)置的屬性存儲在buf指向的msqid構(gòu)造中;可設(shè)置屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同時,也影響msg_ctime成員。IPC_RMID:刪除msqid標(biāo)識的消息隊列;調(diào)用返回:成功返回0,否那么

17、返回-1。三、消息隊列的限制每個消息隊列的容量所能包容的字節(jié)數(shù)都有限制,該值因系統(tǒng)不同而不同。在后面的應(yīng)用實例中,輸出了redhat 8.0的限制,結(jié)果參見附錄3。另一個限制是每個消息隊列所能包容的最大消息數(shù):在redhad 8.0中,該限制是受消息隊列容量制約的:消息個數(shù)要小于消息隊列的容量字節(jié)數(shù)。注:上述兩個限制是針對每個消息隊列而言的,系統(tǒng)對消息隊列的限制還有系統(tǒng)范圍內(nèi)的最大消息隊列個數(shù),以及整個系統(tǒng)范圍內(nèi)的最大消息數(shù)。一般來說,實際開發(fā)過程中不會超過這個限制。-回頁首四、消息隊列應(yīng)用實例消息隊列應(yīng)用相對較簡單,下面實例根本上覆蓋了對消息隊列的所有操作,同時,程序輸出結(jié)果有助于加深對前面

18、所講的某些規(guī)那么及消息隊列限制的理解。#include sys/types.h#include sys/msg.h#include unistd.h void msg_statint,struct msqid_ds;mainint gflags,sflags,rflags;key_t key;int msgid;int reval;struct msgsbufint mtype;char mtext1;msg_sbuf;struct msgmbufint mtype;char mtext10;msg_rbuf;struct msqid_ds msg_ginfo,msg_sinfo;char*m

19、sgpath="/unix/msgqueue";key=ftokmsgpath,'a';gflags=IPC_CREAT|IPC_EXCL;msgid=msggetkey,gflags|00666;ifmsgid=-1printf"msg create errorn";return;/創(chuàng)立一個消息隊列后,輸出消息隊列缺省屬性msg_statmsgid,msg_ginfo;sflags=IPC_NOWAIT;msg_sbuf.mtype=10;msg_sbuf.mtext0='a';reval=msgsndmsgid,&am

20、p;msg_sbuf,sizeofmsg_sbuf.mtext,sflags;ifreval=-1printf"message send errorn";/發(fā)送一個消息后,輸出消息隊列屬性msg_statmsgid,msg_ginfo;rflags=IPC_NOWAIT|MSG_NOERROR;reval=msgrcvmsgid,&msg_rbuf,4,10,rflags;ifreval=-1printf"read msg errorn";else printf"read from msg queue%d bytesn",re

21、val;/從消息隊列中讀出消息后,輸出消息隊列屬性msg_statmsgid,msg_ginfo;msg_sinfo.msg_perm.uid=8;/just atry msg_sinfo.msg_perm.gid=8;/msg_sinfo.msg_qbytes=16388;/此處驗證超級用戶可以更改消息隊列的缺省msg_qbytes/注意這里設(shè)置的值大于缺省值reval=msgctlmsgid,IPC_SET,&msg_sinfo;ifreval=-1printf"msg set info errorn";return;msg_statmsgid,msg_ginf

22、o;/驗證設(shè)置消息隊列屬性reval=msgctlmsgid,IPC_RMID,NULL;/刪除消息隊列ifreval=-1printf"unlink msg queue errorn";return;void msg_statint msgid,struct msqid_ds msg_infoint reval;sleep1;/只是為了后面輸出時間的方便reval=msgctlmsgid,IPC_STAT,&msg_info;ifreval=-1printf"get msg info errorn";return;printf"n&q

23、uot;;printf"current number of bytes on queue is%dn",msg_info.msg_cbytes;printf"number of messages in queue is%dn",msg_info.msg_qnum;printf"max number of bytes on queue is%dn",msg_info.msg_qbytes;/每個消息隊列的容量字節(jié)數(shù)都有限制MSGMNB,值的大小因系統(tǒng)而異。在創(chuàng)立新的消息隊列時,/msg_qbytes的缺省值就是MSGMNB printf

24、"pid of last msgsnd is%dn",msg_info.msg_lspid;printf"pid of last msgrcv is%dn",msg_info.msg_lrpid;printf"last msgsnd time is%s",ctime&msg_info.msg_stime;printf"last msgrcv time is%s",ctime&msg_info.msg_rtime;printf"last change time is%s",ctim

25、e&msg_info.msg_ctime;printf"msg uid is%dn",msg_info.msg_perm.uid;printf"msg gid is%dn",msg_info.msg_perm.gid;程序輸出結(jié)果見附錄3。-回頁首小結(jié):消息隊列與管道以及有名管道相比,具有更大的靈敏性,首先,它提供有格式字節(jié)流,有利于減少開發(fā)人員的工作量;其次,消息具有類型,在實際應(yīng)用中,可作為優(yōu)先級使用。這兩點是管道以及有名管道所不能比的。同樣,消息隊列可以在幾個進(jìn)程間復(fù)用,而不管這幾個進(jìn)程是否具有親緣關(guān)系,這一點與有名管道很相似;但消息隊列是

26、隨內(nèi)核持續(xù)的,與有名管道隨進(jìn)程持續(xù)相比,生命力更強,應(yīng)用空間更大。附錄1:在參考文獻(xiàn)1中,給出了IPC隨進(jìn)程持續(xù)、隨內(nèi)核持續(xù)以及隨文件系統(tǒng)持續(xù)的定義:隨進(jìn)程持續(xù):IPC一直存在到翻開IPC對象的最后一個進(jìn)程關(guān)閉該對象為止。如管道和有名管道;隨內(nèi)核持續(xù):IPC一直持續(xù)到內(nèi)核重新自舉或者顯示刪除該對象為止。如消息隊列、信號燈以及共享內(nèi)存等;隨文件系統(tǒng)持續(xù):IPC一直持續(xù)到顯示刪除該對象為止。附錄2:構(gòu)造msg_queue用來描繪消息隊列頭,存在于系統(tǒng)空間:struct msg_queuestruct kern_ipc_perm q_perm;time_t q_stime;/*last msgsnd

27、 time*/time_t q_rtime;/*last msgrcv time*/time_t q_ctime;/*last change time*/unsigned long q_cbytes;/*current number of bytes on queue*/unsigned long q_qnum;/*number of messages in queue*/unsigned long q_qbytes;/*max number of bytes on queue*/pid_t q_lspid;/*pid of last msgsnd*/pid_t q_lrpid;/*last

28、receive pid*/struct list_head q_messages;struct list_head q_receivers;struct list_head q_senders;構(gòu)造msqid_ds用來設(shè)置或返回消息隊列的信息,存在于用戶空間;struct msqid_dsstruct ipc_perm msg_perm;struct msg*msg_first;/*first message on queue,unused*/struct msg*msg_last;/*last message in queue,unused*/_kernel_time_t msg_stime

29、;/*last msgsnd time*/_kernel_time_t msg_rtime;/*last msgrcv time*/_kernel_time_t msg_ctime;/*last change time*/unsigned long msg_lcbytes;/*Reuse junk fields for 32 bit*/unsigned long msg_lqbytes;/*ditto*/unsigned short msg_cbytes;/*current number of bytes on queue*/unsigned short msg_qnum;/*number o

30、f messages in queue*/unsigned short msg_qbytes;/*max number of bytes on queue*/_kernel_ipc_pid_t msg_lspid;/*pid of last msgsnd*/_kernel_ipc_pid_t msg_lrpid;/*last receive pid*/;/可以看出上述兩個構(gòu)造很相似。附錄3:消息隊列實例輸出結(jié)果:current number of bytes on queue is 0number of messages in queue is 0max number of bytes on

31、queue is 16384 pid of last msgsnd is 0pid of last msgrcv is 0last msgsnd time is Thu Jan 108:00:00 1970 last msgrcv time is Thu Jan 108:00:00 1970 last change time is Sun Dec 29 18:28:20 2002 msg uid is 0msg gid is 0/上面剛剛創(chuàng)立一個新消息隊列時的輸出current number of bytes on queue is 1number of messages in queue is 1max number

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論