进程间通信-消息队列

消息队列:
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,每个数据块都被认为含有一个类型,
接收进程可以独立地接收含有不同类型的数据结构,我们可以通过发送消息来避免命名管道的同步和阻塞.
但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制.
Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度.

相关函数:
int msgget(key_t key, int msgflg);  
用来创建和访问一个消息队列.
key是消息队列的标识符.
msgflg是权限位,表示消息队列的访问权限,msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列
不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识
符(非0整数),失败返回-1.

int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);  
该函数是把消息添加到消息队列中.
msgid是创建时返回的标识符.
msg_ptr是指向准备发送的消息的指针,消息的结构类型有要求,指针msg_ptr指向的消息结构一定是以一个
长整型成员变量开始的结构体.
接收函数将用这个成员来确定消息的类型,所以消息结构要定义成这样:
struct my_message{  
    long int message_type;    // The data you wish to transfer
};
msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括
长整型消息类型成员变量的长度。
msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情.
如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.

int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg); 
该函数是从消息队列中获取消息.
msgid msg_ptr msg_st同上
msgtype可以实现一种简单的接收优先级,如果msgtype为0,就获取队列中的第一个消息.如果它的值大于零,将
获取具有相同消息类型的第一个信息.如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息.
msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情.
调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后
删除消息队列中的对应消息,失败时返回-1.

int msgctl(int msgid, int command, struct msgid_ds *buf);  
command是将要采取的动作,它可以取3个值:
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,去覆盖msgid_ds的值.
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值.
IPC_RMID:删除消息队列.
buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构,msgid_ds结构至少包括以下成员:
struct msgid_ds  
{  
    uid_t shm_perm.uid;  
    uid_t shm_perm.gid;  
    mode_t shm_perm.mode;  

}; 

 

消息接收端代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>

struct msg_st
{
	long int msg_type;
	char text[BUFSIZ];
};

int main()
{
	int running = 1;
	int msgid = -1;
	struct msg_st data;
	long int msgtype = 0; 

	
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);//建立消息队列
	if(msgid == -1)
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	
	while(running)
	{
		if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)//从队列中获取消息,直到遇到end消息为止
		{
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		printf("You wrote: %s\n",data.text);
		if(strncmp(data.text, "end", 3) == 0)//遇到end结束
			running = 0;
	}
	if(msgctl(msgid, IPC_RMID, 0) == -1)//删除消息队列
	{
		fprintf(stderr, "msgctl(IPC_RMID) failed\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}


消息发送端代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>

#define MAX_TEXT 512
struct msg_st
{
	long int msg_type;
	char text[MAX_TEXT];
};

int main()
{
	int running = 1;
	struct msg_st data;
	char buffer[BUFSIZ];
	int msgid = -1;

	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);//建立消息队列
	if(msgid == -1)
	{
		fprintf(stderr, "msgget create error: %d\n", errno);
		exit(EXIT_FAILURE);
	}

	
	while(running)
	{
		
		printf("Enter some text: ");
		fgets(buffer, BUFSIZ, stdin);
		data.msg_type = 1;   
		strcpy(data.text, buffer);//向消息队列中写消息,直到写入end
		if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)//向队列发送数据
		{
			fprintf(stderr, "msgsnd failed\n");
			exit(EXIT_FAILURE);
		}
		
		if(strncmp(buffer, "end", 3) == 0)//输入end结束输入
			running = 0;
		sleep(1);
	}
	exit(EXIT_SUCCESS);
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值