天天看點

消息隊列

努力隻能及格,拼命才能優秀

消息緩沖區結構

結構msgid_ds

結構ipc_perm

鍵值建構ftok()函數

獲得消息msgget()函數

發送消息msgsnd()函數

接收消息msgrcv()函數愛

消息控制msgctl()函數

例子

1.顯示消息屬性的函數msg_show_attr()

2.主函數main()

        消息隊列是核心位址空間中的内部連結清單,通過linux核心在各個程序之間傳遞内容,消息順序地發送消息隊列中,并以幾種不同的方式從隊列中擷取,每個消息隊列可以用ipc辨別符唯一地進行辨別。核心中的消息隊列是通過ipc的辨別符來差別的,不同的消息隊列之間是相對獨立的。每個消息隊列中的消息,又構成一個獨立的連結清單。

        常用的結構是msgbuf結構。程式員可以以這個結構為模闆定義自己的消息結構。在頭檔案<linux/msg.h>中,它的定義如下:

在結構msgbuf中有以下兩個成員。

mtype:消息類型,以正數來表示。使用者可以給某個消息設定一個類型,可以在消息隊列中正确的發送和接收自己的消息。例如,在socket程式設計過程中,一個伺服器可以接收多個用戶端的連接配接,可以為每個用戶端設定一個消息類型,伺服器和用戶端之間的通信可以通過此消息類型來發送和接收消息,并且多個用戶端之間通過消息類型來區分。

mtext:消息資料

        消息資料的類型為char,長度為1。在建構自己的消息結構時,這個域并不一定要設為char或者長度為1。可以根據實際的情況進行設定,這個域能存放任意形式的任意資料,程式員可以重新定義msgbuf結構,例如:

        上面定于的消息結構與系統模闆定義的不一緻,但是mtype是一緻的。消息在通過核心在程序之間收發時,内部不對mtext域進行轉換,任意的消息都可以發送。具體的轉換工作是在應用程式之間進行的。但是,消息的大小,存在一個内部的限制。在linux中,它在linux/msg.h中的定義如下:

        消息總的大小不能超過8192個位元組,這其中包括ntype成員,它的長度是4個位元組(long類型)

        本例在建立消息隊列後,列印其屬性,并在每次發送和接收後均檢視其屬性,最後對消息隊列進行修改。

        核心msgid_ds結構——ipc對象分為3類,每一類都有一個内部資料結構,該資料結構是由核心維護的,對于消息隊列而言,它的内部資料結構是msgid_ds結構,對于系統上建的每個消息隊列,核心均為其建立、存儲和維護該結構的一個執行個體。該結構在<linux/msg.h>中定義:

        核心把ipc對象的許可權限資訊存放在ipc_perm類型的結構中,例如在前面描述的某個消息隊列的内部結構中,msg_perm成員就是ipc_perm類型的,它的定義是在檔案<linux/ipc.h>中,如下所示。

ftok()函數将路徑名和項目的表示符轉變為一個系統v的ipc鍵值。其原型如下:

其中pathname必須是已經存在的目錄,而proj_id則是一個8位的值,通常用a,b等表示。例如建立如下目錄:

然後用如以下代碼生成一個鍵值:

        建立一個新的消息隊列,或者通路一個現由的隊列,可以使用函數msgget(),其原型如下:

        msgget()函數的第一個參數是鍵值,可以用ftok()函數生成,這個關鍵字的值将被拿來與核心中其他消息隊列的現有關鍵字相對比。比較之後,打開或者通路操作依賴于msgflg參數的内容。

ipc_creat:如果在核心中不存在該隊列,則建立它

ipc_excl:當與ipc_creat一起使用時,如果隊列早已存在則将出錯。

        如果隻使用了ipc_creat,msgget()函數或者傳回新建立消息隊列的消息隊列辨別符,或者會傳回現有的具有同一個關鍵字值的隊列的辨別符。如果同時使用了ipc_excl和ipc_creat,那麼将可能會有兩個結果:建立一個新的隊列,如果該隊列存在,則調用将出錯,并傳回-1。ipc_excl本身是沒有什麼用處的,但在與ipc_creat組合使用時,它可以用于保證沒有一個現存的隊列為了通路而被打開。例如,下面的代碼建立一個消息隊列:

        一旦獲得了隊列辨別符,使用者就可以開始在該消息隊列上執行相關操作了。為了向隊列傳遞消息,使用者可以使用msgsnd()函數:

        msgsnd()函數的第一個參數是隊列辨別符,它是前面調用msgget()獲得的傳回值。第二個參數是msgp,它是一個void類型的指針,指向一個消息緩沖區。msgsz參數則包含着消息的大小,它是以位元組為機關的,其中不包括消息類型的長度(4個位元組長)。

        msgflg參數可以設定為0(表示忽略),也可以設定為ipc_nowait。如果消息隊列已滿,則消息将不會被寫入到隊列中。如果沒有指定ipc_nowait,則調用程序将被中斷(阻塞),直到可以寫消息為止,例如,如下代碼已經打開消息隊列發送資訊:

        首先将要發送的消息打包到msg_mbuf.mtext域中,然後調用msgsnd發送消息給核心。這裡的mtype設定了類型為10,當接收時必須設定此域為10,才能接收到這時發送的消息。msgsnd()函數的msg_id時之前msgget建立的。

        當獲得隊列辨別符後,使用者就可以開始在該消息隊列上執行消息隊列的接收操作。msgrev()函數用于接收隊列辨別符中的消息,函數原型如下:

msgrcv()函數的第1個參數msqid是用來指定,在消息擷取過程中所使用的隊列(該值是由前面調用msgget()得到的傳回值)

第二個參數msgp代表消息緩沖區變量的位址,擷取的消息将存放在這裡

第三個參數msgsz代表喜喜緩沖區結構的大小,不包括mtype成員的長度

第四個參數mtype指定要從隊列中擷取的消息類型。核心将查找隊列中具有比對類型的第一個到達的消息,并把它複制傳回由msgp參數所指定的位址中。如果mtype參數傳送一個為0的值,則将傳回隊列中最老的消息,不管消息的類型是什麼。

        如果把ipc_nowait作為一個标志傳送給該函數,而隊列中沒有任何消息,則該此調用将會向調用程序傳回enomsg。否則,調用程序将阻塞,直到滿足msgrcv()參數的消息到達隊列為止。如果在客戶等待消息的時候隊列被删除了,則傳回eidrm。如果在程序阻塞并等待消息的到來時捕獲到一個信号,則傳回eintr。函數msgrcv的使用代碼如下:

        上面的代碼中将mtype設定為10,可以獲得之前發送的核心的消息獲得(因為之前發送的mtype值也設定為10),msgrcv傳回值為接收到的消息長度。

        為了在一個消息隊列上執行控制操作,使用者可以使用msgctl()函數。

        msgctl()向核心發送一個cmd指令,核心根據此來判斷進行何種操作,buf為應用層和核心空間進行資料交換的指針。其中cmd可以為如下值:

ipc_stat:獲得隊列的msqid_ds結構,并把它存放在buf變量所指定的位址中,通過這種方式,應用層可以獲得目前消息隊列的設定情況,例如是否有消息到來、消息隊列的緩沖區設定等。

ipc_set:設定隊列的msqid_ds結構的ipc_perm成員值,它是從buf中取得該值的。通過ipc_set指令,應用層可以設定消息隊列的狀态,例如修改消息隊列的權限,使其他使用者可以通路或者不能通路目前的隊列;甚至可以設定消息隊列的某些目前值來僞裝。

ipc_rmid:核心删除隊列。使用此指令執行後,核心會把此消息隊列從系統中删除。

        msg_show_attr()函數根據使用者輸入的消息id,将消息隊列中的位元組數、消息數、最大位元組數、最後發送消息的程序、最後接收消息的程序、最後發送消息的時間、最後接收消息的時間、最後消息變換時間,以及消息的uid和gid等資訊進行列印。

        主函數先用函數ftok()使用路徑"./"獲得一個鍵值,之後進行相關的操作并列印消息的屬性。

調用函數msgget()獲得一個消息後,列印消息的屬性。

調用函數msgsnd()發送一個消息後,列印消息的屬性。

調用函數msgrcv()接收一個消息後,列印消息的屬性。

c