Linux POSIX Message Queue 使用体会

最近正在Linux上使用POSIX Message Queue(以下简称MQ)在进程间通讯,对目前我这系统发行版和编译器来讲,MQ用起来有一点体会,是教程是没有说明的,或者我看的不够仔细,没有发现疑问


参考资料

《The Linux Programming Interface - A Linux and UNIX System Programming Handbook》2010


测试系统:

Linux Mint 3.11.0-12-generic x86_64 GNU/Linux, MPICH2, mpic++ (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1


先上代码


// UNIX IPC functionalities
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
// POSIX Message Queue
#include <mqueue.h>

// C++ header files
#include <iostream>
#include <sstream>
#include <string>


int receiveMsg(mqd_t *mqdes)
{
	unsigned int prio;   // priority of the message
	struct mq_attr attr; // attribute
	ssize_t numRead;     // size of message

	if (mqdes == NULL)
	{
		std::cout << "mqdes == NULL" << std::endl;
		exit(EXIT_FAILURE);
	}

	do
	{
		sleep(1);

		std::cout << "Check for new message." << std::endl;

		if (mq_getattr(*mqdes, &attr) == -1)
		{
			// this is an error
			std::cout << "In receiveMsg(), get attribute error." << std::endl;
			exit(EXIT_FAILURE);
		}
	}while (attr.mq_curmsgs == 0);

	// allocate memory for the incoming messages
	char * buffer = (char *)malloc(attr.mq_msgsize);
	if (buffer == NULL)
	{
		std::cout << "In receiveMsg(), malloc error." << std::endl;
		exit(EXIT_FAILURE);
	}
	memset(buffer,0,attr.mq_msgsize);
	// test use
//	memset(buffer,1,attr.mq_msgsize);

	for (int i=0;i<attr.mq_curmsgs;++i)
	{
		numRead = mq_receive(*mqdes, buffer, attr.mq_msgsize, &prio);
		if (numRead == -1)
		{
			std::cout << "In receiveMsg(), mq_receive() error." << std::endl;
			exit(EXIT_FAILURE);
		}

		// print the message to the standard output
		std::cout << "In receiveMsg(), buffer = "
				  << buffer
				  << ", with strlen(buffer) = "
				  << strlen(buffer)
				  << std::endl;

		std::cout << "buffer = ";

		for (int j=0;j<strlen(buffer);++j)
		{
			std::cout << (unsigned int)(buffer[j]) << " ";
		}

		std::cout << std::endl;
	}

	free(buffer);

	return 0;
}

int main(int argc, char *argv[])
{
	// create the POSIX message queue
	mqd_t mqdes;         // descriptor

	mqdes = mq_open("/mymq", O_CREAT | O_RDWR | O_NONBLOCK, 0666, NULL);

	if (mqdes == (mqd_t) -1)
	{
		std::cout << "Open MQ failed!" << std::endl;
		exit(EXIT_FAILURE);
	}

	// begin to receive message
	if (receiveMsg(&mqdes) != 0)
	{
		std::cout << "receiveMsg() returns error code." << std::endl;
	}

	mq_close(mqdes);
	mq_unlink("/mymq");

	exit(EXIT_SUCCESS);
}

话不多说啦,体会:

=========== 体会开始 ==============

Message其实是byte计数的内存数据,不是字符串!

=========== 体会结束 ==============


Message这名字起的挺广泛,而且看手册,举的例子也是传输的字符串。于是在自己实现时,就想当然的认为MQ其实时传输的是字符串,但这是不对的。


今天实际调试时就出现了这个问题,具体表现形式是mq_receive()函数调用以后,buffer里正常字符串结尾有好多奇怪的字符。刚开始还感觉是不是字符编码的问题,在OS上查了一圈,感觉又不像,最后发现问题出在没有对buffer进行初始化。


使用没有初始化的内存是禁忌的,但是当时调试时偷懒了,因为下意识地认为,发送的Message是字符串,言下之意是一定有一个结尾'\0'字符自动添加到buffer里。其实不是这样的,在《手册》的实例中,也明确表达了,发送的Message的长度是一个字符串的strlen()结果,就是说,不包括最后一个'\0'。虽然发送时以一个字符串的头地址作为待发送内容的起始,但是最终发送的长度仅是strlen(),比实际的字符串占用内存少了一个byte。在mq_receive()时,MQ也不会自动添加最后一个'\0',因为没这个必要 ---- Message压根就不是字符串。


所以回顾mq_receive()函数的声明,恍然大悟

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);


返回值就是指的当前接收的message的byte数,是个非常重要的值,因为Message不是字符串。


现在理解了,MQ的Message事实上是一段用byte计数的内存,MQ将这块内存以消息的形式发送给kernel,其他进程再从kernel中获取(复制)这块内存中的数据。


事实上,要是就想发送字符串,有两种方法,要么发送时多发一个字节,要么接收之前将buffer初始化,并且一定要初始化为0,否则就会出现我今天早些时候遇到的问题,尾巴上一大堆诡异的字符(可以通过receiveMsg()中的memset()调试这个bug)。

P.S.: 发送Message用的是python2.7代码,从这里获取,安装之前需要安装python2.7-dev。

https://pypi.python.org/pypi/posix_ipc



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统中,可以通过System V和POSIX两种方式实现Message Queue。 System V的Message Queue是一种IPC机制,可以在不同进程之间传递消息。使用System V Message Queue需要包含以下头文件: ``` #include <sys/msg.h> #include <sys/ipc.h> ``` 创建一个Message Queue需要使用一个键值,这个键值可以由ftok()函数生成。其参数包括一个已存在的文件路径和一个整数标识符,然后ftok()会根据这两个参数生成一个不重复的键值。示例代码如下: ``` key_t key = ftok("/tmp/myfile", 'q'); ``` 创建一个System V Message Queue需要使用msgget()函数。该函数的第一个参数为键值,第二个参数为权限位,第三个参数为标志位。例如: ``` int msqid = msgget(key, 0666 | IPC_CREAT); ``` 发送消息到 Message Queue 使用 msgsnd() 函数,接收消息则使用 msgrcv() 函数。这两个函数的使用详细说明可以参考 Linux 系统中的 man pages。 POSIX Message QueueLinux中的一种消息队列机制,相比于System V Message QueuePOSIX Message Queue更加方便和安全。POSIX Message Queue的头文件为: ``` #include <mqueue.h> ``` 创建一个 POSIX Message Queue 需要使用mq_open()函数,参数包括消息队列名称,权限位,和属性参数。例如: ``` mqd_t mqd = mq_open("/my_queue", O_WRONLY | O_CREAT, 0666, NULL); ``` 发送消息到 Message Queue 使用 mq_send() 函数,接收消息则使用 mq_receive() 函数。这两个函数的使用详细说明可以参考 Linux 系统中的 man pages。 在使用Message Queue后,需要关闭并且删除它。对于小写的System V Message Queue使用msgctl()函数。对于POSIX Message Queue使用mq_close()和mq_unlink()函数。例如: ``` // System V Message Queue msgctl(msqid, IPC_RMID, NULL); // POSIX Message Queue mq_close(mqd); mq_unlink("/my_queue"); ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值