Linux编程基础之进程间通信之五:消息队列

这篇博客介绍了Linux编程中的消息队列,包括其概述、一般使用原理和相关函数的详细说明。通过msgget(), msgsnd(), msgrcv()和msgctl()四个主要函数,阐述了消息队列的创建、添加消息、读取消息和控制消息队列的操作。还提供了测试用例的简要介绍。" 130295573,17798234,Caché数据库在实验室资源管理系统中的应用,"['数据库', '开发语言', 'Java', '资源管理', '程序员']
摘要由CSDN通过智能技术生成

一、消息队列的概述

消息队列,列就是一些消息的列表。用户可以从消息队列中添加消息和读取消息等。从这点上看,消息队列具有一定的FIFO 特性,但是它可以实现消息的随机查询,比FIFO 具有更大的优势。同时,这些消息又是存在于内核中的,由“队列ID”来标识。


二、消息队列的一般使用原理和函数说明

1、一般使用原理

消息队列的实现包括创建或打开消息队列、添加消息、读取消息和控制消息队列这4 种操作。其中创建或打开消息队列使用的函数是msgget(),这里创建的消息队列的数量会受到系统消息队列数量的限制;添加消息使用的函数是msgsnd()函数,它把消息添加到已打开的消息队列末尾;读取消息使用的函数是msgrcv(),它把消息从消息队列中取走,与FIFO 不同的是,这里可以指定取走某一条消息;最后控制消息队列使用的函数是msgctl(),它可以完成多项功能。

2、常用函数的说明

a、获得或者创建消息队列的函数

int msgget(key_t key, int msgflg)
        key : 消息队列的键值,多个进程可以通过它访问同一个消息队列,其中有个特殊值IPC_PRIVATE。它用于创建当前进程的私有消息队列

        msgflg : 权限标志位

        返回值:成功返回消息队列ID,失败返回-1

b、添加一个消息到消息队列

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
        msgid : 消息队列的队列ID

        msgp : 指向消息结构的指针。该消息结构msgbuf 通常为:

struct msgbuf
{
long mtype; /* 消息类型,该结构必须从这个域开始 */
char mtext[1]; /* 消息正文 */
}
        msgsz : 消息正文的字节数(不包括消息类型指针变量)

        msgflg :IPC_NOWAIT 若消息无法立即发送(比如:当前消息队列已满),函数会立即返回;0:msgsnd 调阻塞直到发送成功为止

        返回值:成功返回0,失败返回-1

c、从消息队列中取出一个消息

int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
        msgid : 消息队列的队列ID

        msgp : 消息缓冲区, 同于msgsnd()函数的msgp

        msgsz : 消息正文的字节数(不包括消息类型指针变量)

        msgtype : 0:接收消息队列中第一个消息;大于0:接收消息队列中第一个类型为msgtyp 的消息;小于0:接收消息队列中第一个类型值不小于msgtyp 绝对值且类型值又最小的消息

        msgflg : MSG_NOERROR:若返回的消息比msgsz 字节多,则消息就会截短到msgsz 字节,且不通知消息发送进程;IPC_NOWAIT 若在消息队列中并没有相应类型的消息可以接收,则函数立即返回;0:msgsnd()调用阻塞直到接收一条相应类型的消息为止;

        返回值:成功返回0,失败返回-1

d、消息队列的控制函数

int msgctl (int msgqid, int cmd, struct msqid_ds *buf )
        msqid : 消息队列的队列ID

        cmd : IPC_STAT:读取消息队列的数据结构msqid_ds,并将其存储在buf 指定的地址中;IPC_SET:设置消息队列的数据结构msqid_ds 中的ipc_perm 域(IPC 操作权限描述结构)值。这个值取自buf 参数;IPC_RMID:从系统内核中删除消息队列
        buf : 描述消息队列的msgqid_ds 结构类型变量

        返回值:成功返回0,失败返回-1

三、测试

编写一个消息队列的测试例程:

msg_rcv.c :创建一个消息队列,并不断的将消息队列中的消息读取出来,没有消息就阻塞等待,接收到quit消息就退出

msg_snd.c : 创建一个消息,将消息添加到消息队列,消息的信息从用户空间传入

msg_rcv.c的具体实现如下:

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

/* 定义消息的大小 */
#define MESSAGE_SIZE	256

/* 定义一个结构体作为消息的基本单元 */
struct msgbuf {
   long mtype;       			/* message type, must be > 0 */
   char mtext[MESSAGE_SIZE];    /* message data */
};


/*	消息队列的接收端,接收从发送端发送过来的消息
 *		
 */
int main(void)
{
	key_t key;
	int msgid;
	int ret;

	struct msgbuf msg;

	/* 构造一个消息队列的键值 */
	key = ftok(".", 0x03);
	if(-1 == key)
	{
		printf("ftok error!\n");
		return -1;
	}
	
	/* 创建一个消息队列 */
	msgid = msgget(key, 0666 | IPC_CREAT);
	if(-1 == msgid)
	{
		printf("msgget error!\n");
		return -1;
	}

	/* 不停的接收从发送端发来的消息,收到: quit 退出 */
	while(1)
	{
		/* 初始化消息单元 */
		memset(msg.mtext, 0, MESSAGE_SIZE);

		/* 从消息队列中取出第一个消息 */
		ret = msgrcv(msgid, &msg, MESSAGE_SIZE, 0, 0);
		if(-1 == ret)
		{
			printf("msgrcv error!\n");
			return -1;
		}

		/* 打印接收来的消息 */
		printf("message form : %ld, message : %s\n", msg.mtype, msg.mtext);

		/* 判断接收到的消息是否是 : quit */
		if(strncmp(msg.mtext, "quit", 4) == 0)
		{
			printf("quit!!!\n");
			goto out;
		}
	}

out:
	/* 将消息队列从系统中移除 */
	ret = msgctl(msgid, IPC_RMID, NULL);
	if(-1 == ret)
	{
		printf("msgctl error!\n");
		return -1;
	}

	return 0;
}
msg_snd.c的具体实现如下:

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

/* 定义消息的大小 */
#define MESSAGE_SIZE	256

/* 定义一个结构体作为消息的基本单元 */
struct msgbuf {
   long mtype;       			/* message type, must be > 0 */
   char mtext[MESSAGE_SIZE];    	/* message data */
};


/*	消息队列的发送端,发送一条消息给接收端
 *		usage : msg_snd <msg>
 */
int main(int argc, char *argv[])
{
	key_t key;
	int msgid;
	int ret;

	struct msgbuf msg;

	if(2 != argc)
	{
		printf("usage : %s <msg>\n", argv[0]);
		return -1;
	}

	/* 构造一个消息队列的键值 */
	key = ftok(".", 0x03);
	if(-1 == key)
	{
		printf("ftok error!\n");
		return -1;
	}

	/* 获得或者创建一个消息队列 */
	msgid = msgget(key, 0666 | IPC_CREAT);
	if(-1 == msgid)
	{
		printf("msgget error!\n");
		return -1;
	}

	/* 初始化消息缓冲区 */
	memset(msg.mtext, 0, MESSAGE_SIZE);

	/* 构造一个消息单元 */
	msg.mtype = getpid();			// 设置消息类型为当前进程的pid
	strcpy(msg.mtext, argv[1]);		// 将用户输入的消息写入消息队列中

	/* 将消息添加到消息队列 */
	ret = msgsnd(msgid, &msg, strlen(msg.mtext), 0);
	if(-1 == ret)
	{
		printf("msgsnd error!\n");
		return -1;
	}

	/* 打印发送消息的信息 */
	printf("pid : %ld, message : %s\n", msg.mtype, msg.mtext);

	return 0;
}
编译并运行结果如下所示:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值