訊息佇列函式以及其簡單使用

wzm10455發表於2013-01-21

訊息佇列函式由msgget、msgctl、msgsnd、msgrcv四個函式組成。下面的表格列出了這四個函式的函式原型及其具體說明。

1.   msgget函式原型

msgget(得到訊息佇列識別符號或建立一個訊息佇列物件)

所需標頭檔案

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函式說明

得到訊息佇列識別符號或建立一個訊息佇列物件並返回訊息佇列識別符號

函式原型

int msgget(key_t key, int msgflg)

函式傳入值

key

0(IPC_PRIVATE):會建立新的訊息佇列

大於0的32位整數:視引數msgflg來確定操作。通常要求此值來源於ftok返回的IPC鍵值

msgflg

0:取訊息佇列識別符號,若不存在則函式會報錯

IPC_CREAT:當msgflg&IPC_CREAT為真時,如果核心中不存在鍵值與key相等的訊息佇列,則新建一個訊息佇列;如果存在這樣的訊息佇列,返回此訊息佇列的識別符號

IPC_CREAT|IPC_EXCL:如果核心中不存在鍵值與key相等的訊息佇列,則新建一個訊息佇列;如果存在這樣的訊息佇列則報錯

函式返回值

成功:返回訊息佇列的識別符號

出錯:-1,錯誤原因存於error中

附加說明

上述msgflg引數為模式標誌引數,使用時需要與IPC物件存取許可權(如0600)進行|運算來確定訊息佇列的存取許可權

錯誤程式碼

EACCES:指定的訊息佇列已存在,但呼叫程式沒有許可權訪問它

EEXIST:key指定的訊息佇列已存在,而msgflg中同時指定IPC_CREAT和IPC_EXCL標誌

ENOENT:key指定的訊息佇列不存在同時msgflg中沒有指定IPC_CREAT標誌

ENOMEM:需要建立訊息佇列,但記憶體不足

ENOSPC:需要建立訊息佇列,但已達到系統的限制

如果用msgget建立了一個新的訊息佇列物件時,則msqid_ds結構成員變數的值設定如下:

Ÿ        msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime設定為0。

Ÿ        msg_ctime設定為當前時間。

Ÿ        msg_qbytes設成系統的限制值。

Ÿ        msgflg的讀寫許可權寫入msg_perm.mode中。

Ÿ        msg_perm結構的uid和cuid成員被設定成當前程式的有效使用者ID,gid和cuid成員被設定成當前程式的有效組ID。

2.   msgctl函式原型

msgctl (獲取和設定訊息佇列的屬性)

所需標頭檔案

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函式說明

獲取和設定訊息佇列的屬性

函式原型

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

函式傳入值

msqid

訊息佇列識別符號

cmd

 

IPC_STAT:獲得msgid的訊息佇列頭資料到buf中

IPC_SET:設定訊息佇列的屬性,要設定的屬性需先儲存在buf中,可設定的屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes

buf:訊息佇列管理結構體,請參見訊息佇列核心結構說明部分

函式返回值

成功:0

出錯:-1,錯誤原因存於error中

錯誤程式碼

EACCESS:引數cmd為IPC_STAT,確無許可權讀取該訊息佇列

EFAULT:引數buf指向無效的記憶體地址

EIDRM:識別符號為msqid的訊息佇列已被刪除

EINVAL:無效的引數cmd或msqid

EPERM:引數cmd為IPC_SET或IPC_RMID,卻無足夠的許可權執行

3.   msgsnd函式原型

msgsnd (將訊息寫入到訊息佇列)

所需標頭檔案

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函式說明

將msgp訊息寫入到識別符號為msqid的訊息佇列

函式原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

函式傳入值

msqid

訊息佇列識別符號

msgp

傳送給佇列的訊息。msgp可以是任何型別的結構體,但第一個欄位必須為long型別,即表明此傳送訊息的型別,msgrcv根據此接收訊息。msgp定義的參照格式如下:

    struct s_msg{ /*msgp定義的參照格式*/
     long type; /* 必須大於0,訊息型別 */
           char mtext[256]; /*訊息正文,可以是其他任何型別*/
    } msgp;

msgsz

要傳送訊息的大小,不含訊息型別佔用的4個位元組,即mtext的長度

msgflg

0:當訊息佇列滿時,msgsnd將會阻塞,直到訊息能寫進訊息佇列

IPC_NOWAIT:當訊息佇列已滿的時候,msgsnd函式不等待立即返回

IPC_NOERROR:若傳送的訊息大於size位元組,則把該訊息截斷,截斷部分將被丟棄,且不通知傳送程式。

函式返回值

成功:0

出錯:-1,錯誤原因存於error中

錯誤程式碼

EAGAIN:引數msgflg設為IPC_NOWAIT,而訊息佇列已滿

EIDRM:識別符號為msqid的訊息佇列已被刪除

EACCESS:無許可權寫入訊息佇列

EFAULT:引數msgp指向無效的記憶體地址

EINTR:佇列已滿而處於等待情況下被訊號中斷

EINVAL:無效的引數msqid、msgsz或引數訊息型別type小於0

   msgsnd()為阻塞函式,當訊息佇列容量滿或訊息個數滿會阻塞。訊息佇列已被刪除,則返回EIDRM錯誤;被訊號中斷返回E_INTR錯誤。

 如果設定IPC_NOWAIT訊息佇列滿或個數滿時會返回-1,並且置EAGAIN錯誤。

msgsnd()解除阻塞的條件有以下三個條件:

①    不滿足訊息佇列滿或個數滿兩個條件,即訊息佇列中有容納該訊息的空間。

②    msqid代表的訊息佇列被刪除。

③    呼叫msgsnd函式的程式被訊號中斷。

4.   msgrcv函式原型

msgrcv (從訊息佇列讀取訊息)

所需標頭檔案

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函式說明

從識別符號為msqid的訊息佇列讀取訊息並存於msgp中,讀取後把此訊息從訊息佇列中刪除

函式原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,

                      int msgflg);

函式傳入值

msqid

訊息佇列識別符號

msgp

存放訊息的結構體,結構體型別要與msgsnd函式傳送的型別相同

msgsz

要接收訊息的大小,不含訊息型別佔用的4個位元組

msgtyp

0:接收第一個訊息

>0:接收型別等於msgtyp的第一個訊息

<0:接收型別等於或者小於msgtyp絕對值的第一個訊息

msgflg

0: 阻塞式接收訊息,沒有該型別的訊息msgrcv函式一直阻塞等待

IPC_NOWAIT:如果沒有返回條件的訊息呼叫立即返回,此時錯誤碼為ENOMSG

IPC_EXCEPT:與msgtype配合使用返回佇列中第一個型別不為msgtype的訊息

IPC_NOERROR:如果佇列中滿足條件的訊息內容大於所請求的size位元組,則把該訊息截斷,截斷部分將被丟棄

函式返回值

成功:實際讀取到的訊息資料長度

出錯:-1,錯誤原因存於error中

錯誤程式碼

E2BIG:訊息資料長度大於msgsz而msgflag沒有設定IPC_NOERROR

EIDRM:識別符號為msqid的訊息佇列已被刪除

EACCESS:無許可權讀取該訊息佇列

EFAULT:引數msgp指向無效的記憶體地址

ENOMSG:引數msgflg設為IPC_NOWAIT,而訊息佇列中無訊息可讀

EINTR:等待讀取佇列內的訊息情況下被訊號中斷

msgrcv()解除阻塞的條件有以下三個:

①    訊息佇列中有了滿足條件的訊息。

②    msqid代表的訊息佇列被刪除。

③    呼叫msgrcv()的程式被訊號中斷。

/*
 ============================================================================
 Name        : msgget.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
//ipcs -q 檢視訊息佇列
#define N 512
#define size 100
struct mshbuf
{
	long mtype;
	char mtext[N];
	char text[size];
};
int main(void) {
	int msgid; //從0開始
	struct mshbuf msgbuf,rcvbuf;
	msgid=msgget(999,0666|IPC_CREAT);
	if(msgid==-1)
	{
		perror("msgget error");
		return -1;
	}

	printf("megid=%d \n",msgid);
	msgbuf.mtype=1L;//大於0的非負整數;
	strcpy(msgbuf.mtext,"hello");
	strcpy(msgbuf.text,"  world!");
	if(msgsnd(msgid,&msgbuf,N+size,0)<0)//0為阻塞的時候的傳送,N為訊息正文的型別,第一個為訊息號,第二個引數為引數
	{
		perror("msgsnd error");
		return -1;
	}

	if(msgrcv(msgid,&rcvbuf,N+size,1L,0)<0)
	{
		perror("msgrcv error");
		return -1;
	}

	printf("rcvbuf.mtext is %s \n",rcvbuf.mtext);
	printf("rcvbuf.text is %s  \n",rcvbuf.text);
	if(msgctl(msgid,IPC_RMID,NULL)<0)
	{
		perror("msgctl error");
		return -1;
	}
	return 0;
}

相關文章