消息队列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]#


 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值