消息隊列2

 

說明:只供學習交流,裝載請註明出處

 

六,msgsnd函數

創建完消息隊列後,爲了通過消息隊列進行進程間的通信,信息的發送方必須向消息隊列發送信息。信息的接收方需要從消息隊列中接收消息。發送消息和接收消息使用的函數分別是msgsnd函數和msgrcv函數。msgsnd函數的具體信息如下表:

msgsnd函數

 

頭文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數原型

int msgsnd(int msqid, const void *msgp,

size_t msgsz, int msgflg);

返回值

成功

失敗

是否設置errno

0

-1

說明:msgsnd函數用於向消息隊列中發送消息。參數msqid爲要將消息發送到的消息隊列。參數msgp爲指向msgbuf結構體的指針,其定義如下:

struct msgbuf

{

           longmtype; //消息類型,可以爲大於0的任意整數

char mtext[1]; //消息文本,文本的大小由msgsnd函數中的參數msgsz確定

};

參數msgsz爲所發送消息的字節數。msgflg可以爲0(忽略該參數)或使用IPC_NOWAIT

如果消息隊列中有足夠的空間,msgsnd函數立即返回,並將msgp指向的消息添加到指定消息隊列中。消息隊列可容納的最大消息量在msg_bytes中給出,該值在創建消息隊列時被初始化爲MSGMNB,當然可以通過msgctl函數修改該限制。

 

如果消息隊列已經達到了最大消息量,msgsnd函數將阻塞(參數msgflg沒有使用IPC_NOWAIT情況下,如果使用了該參數,msgsnd將調用失敗,同時,將errno設置爲EAGAIN),直到消息隊列中有足夠的空間。

 

成功調用msgsnd函數後,將更新msqid_ds結構體中的如下成員:

msg_lspid:調用進程的進程號。

msg_qnum:加1

msg_stime:設置爲當前的時間。

 

錯誤信息:

EACCES:調用msgsnd函數的進程沒有向消息隊列發送消息的權限。

EAGAIN:消息隊列達到最大信息量,同時msgflg中使用了IPC_NOWAIT參數。

EFAULTmsgp指向的非法地址空間。

EIDRM:消息隊列被刪除。

EINTRmsgsnd函數調用被信號中斷。

EINVAL:非法的msqid值、mtype爲負數或msgsz不合法(小於0或大於系統規定的MSGMAX值)。

ENOMEM:系統空間不足。

 

實例:

程序爲使用msgsnd函數的實例。程序首先調用msgsnd函數,向消息隊列中發送消息,然後,調用msgctl函數來獲得消息隊列的相關信息,以確認消息隊列中是否存在發送來的消息。具體代碼如下:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>

typedef struct
{
	long mtype;
	char mtext[BUFSIZ];
}msg_info;

//創建消息隊列
int creat_msg_queue()
{
	key_t key;
	int proj_id;
	int msqid;

	struct msqid_ds buffer;

	proj_id = 3;
	key = ftok("./hello", proj_id);
	if (key == -1)
	{
		perror("Cannot generate the IPC key");
		return (-1);
	}

	msqid = msgget(key, IPC_CREAT|0660);
	if (msqid == -1)
	{
		perror("Cannot create message queue resource");
		return (-1);
	}

	return (msqid);
}

//給指定消息隊列發送消息
int send_msg(int msqid, char *msg)
{
	int result;

	msg_info buf;

	buf.mtype = 100;
	strcpy(buf.mtext, msg);

	result = msgsnd(msqid, &buf, strlen(msg), 0);
	if (result == -1)
	{
		perror("Cannot send message to the message queue");
	}

	return (result);
}

//顯示消息隊列的信息
int show_msg_queue_stat(int msqid)
{
	struct msqid_ds buffer;
	int flg;

	flg = msgctl(msqid, IPC_STAT, &buffer);
	if (flg == -1)
	{
		perror("Cannot get status of the message queue");
		return (-1);
	}

	printf("======Message Queue Info======\n");
	printf("effective user of id : %d\n", buffer.msg_perm.uid);
	printf("effective group of id : %d\n", buffer.msg_perm.gid);
	printf("message queue's creator user id : %d\n", buffer.msg_perm.cuid);
	printf("message queue's creator user id : %d\n", buffer.msg_perm.cgid);
	printf("access mode : %x\n", buffer.msg_perm.mode);

	printf("Maximum number of bytes allowed in message queue: %d\n", 
					(int)buffer.msg_qbytes);
	printf("Current number of bytes in message queue(non-standard) : %d\n",
				(long unsigned int)buffer.__msg_cbytes);

	printf("Current number of message in message queue : %d\n",
				(msgqnum_t)buffer.msg_qnum);

	return (0);
}

int main(void)
{
	int msqid;

	if (msqid = creat_msg_queue()<0)
	{
		printf("Create msg queue fail\n");
		return (-1);
	}

	if (send_msg(msqid, "test message") < 0)
	{
		printf("Send message failure\n");
		return (-1);
	}

	if (show_msg_queue_stat(msqid) < 0)
	{
		printf("Show message queue fail\n");
		return (-1);
	}

	return (0);
}

運行結果:
[root@localhost test]# ./msgsnd 
======Message Queue Info======
effective user of id : 0
effective group of id : 0
message queue's creator user id : 0
message queue's creator user id : 0
access mode : 1b0
Maximum number of bytes allowed in message queue: 65536
Current number of bytes in message queue(non-standard) : 12
Current number of message in message queue : 1
[root@localhost test]# ipcs -q

------ Message Queues --------
key  msqid    owner      perms   used-bytes   messages    
0x03021077 0   root       660        12           1           

[root@localhost test]#


 

七,msgrcv函數

要接收消息隊列中的消息,需要使用msgrcv函數。該函數的具體信息如下表:

 

頭文件

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/types.h>

函數原型

size_t msgrcv(int msqid, void *msgp,

long msgtyp, int msgflg);

返回值

成功

失敗

是否設置errno

收到消息的字節數

-1

函數功能:msgrcv函數從msgid代表的消息隊列中讀取一個消息,並將消息存儲在msgp指向的緩衝結構中。該緩衝結構的定義類似於msgbuf結構體。

參數說明:msqid爲要成中讀取消息的消息隊列標識符;msgp爲指向消息內容的指針;msgszmsgbuf結構體中mtext成員的長度(即消息內容的長度);msgtyp爲請求的消息類型,如果msgtyp0,消息隊列中的第一條消息將被讀取,而不管類型。如果msgtyp大於0,消息隊列中同類型的消息將被讀取。如果在msgflg中設置了MSG_RXCEPT位,將讀取出指定類型的其他消息。如果msgtyp小於0,將讀取絕對值小於msgtyp的消息; msgflg爲指定的處理方式,可以取一下值:

IPC_NOWAIT:如果沒有滿足條件的消息,調用立即返回,此時,errnoENOMSG

IPC_EXCEPT:與msgtyp>0配合使用,返回隊列中第一個類型不爲msgtyp的消息。

IPC_NOERROR:如果隊列中滿足條件的消息內容大於所請求的msgsz字節,則把該消息截斷,截斷部分將丟失。

 

如果消息隊列中沒有要獲得的消息類型(有參數msgtyp指定),且msgflg參數沒有設置IPC_NOWAIT位,msgrcv函數將處於阻塞狀態,直到以下情況發生:

1):消息隊列中收到了進程要獲得的消息。

2):消息隊列被刪除,msgrcv系統調用失敗。

3):調用過程中接收到了中斷。

 

當成功獲得所需消息後,將更新msqid_ds結構體中的如下成員:

msg_lrpid:被設置成調用msgrcv函數的進程。

msg_qnum:減1

msg_rtime:被設置成系統當前時間。

 

錯誤信息:

E2BIG:接收到消息的長度超過參數msgsz中指定的長度,同時,參數msgflg沒有設置MSG_NOERROR位。

EACCES:進程無讀取消息隊列中消息的權限。

EAGAIN:消息隊列中無所要獲得類型的消息,且msgflg沒有設置IPC_NOWAIT位。

EFAULT:參數msgp執行非法地址空間。

EIDRM:當進程處於阻塞狀態等待要獲得類型的消息時,消息隊列被刪除。

EINTR:當進程處於阻塞狀態等待要獲得類型的消息時,接收到信號。

EINVAL:非法的msqid值或msgsz小於0

ENOMSGmsgflg中指定了IPC_NOWAIT位,而消息隊列中沒有要獲取的消息。

 

實例:

程序通過調用msgrcv函數實現了讀取消息隊列中指定消息的功能。讀取消息隊列中信息的函數爲recv_msg,函數的參數意義如下:

1):msqid:消息隊列標識符。

2):msg_type:消息類型,該消息類型與調用時發送的類型要一致。

3):msg:接收到消息內容將保存在該指針的空間中。

 

具體代碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

typedef struct 
{
	long mtype;
	char mtext[BUFSIZ];
}msg_info;

int recv_msg(int msqid, int msg_type, char *msg)
{
	int result;
	msg_info buffer;

	result = msgrcv(msqid, &buffer, BUFSIZ, msg_type, 0);
	if (result == -1)
	{
		perror("Cannot receive message from the queue");
	}

	strcpy(msg, buffer.mtext);

	return (result);

}

int main(int argc, char *argv[])
{
	char buf[BUFSIZ] = {'\0'};

	int msqid;
	int msg_type;
	int result;

	if (argc != 3)
	{
		printf("Usage: %s msqid message_type");
		return (-1);
	}

	msqid = atoi(argv[1]);
	msg_type=atoi(argv[2]);

	result = recv_msg(msqid, msg_type, buf);
	if (result == -1)
	{
		printf("Cannot get message\n");
		return (-1);
	}
	else
	{
		printf("Message queue id: %d message type : %d message : %s\n",
					msqid, msg_type, buf);
	}

	return (0);
}

運行結果:
[root@localhost test]# ./msgrcv 0 100
Message queue id: 0 message type : 100 message : test message
[root@localhost test]# ipcs -q

------ Message Queues --------
key msqid  owner      perms      used-bytes   messages    
0x03021077 0  root       660        0            0           

[root@localhost test]#


 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章