一、前言
boost中的消息队列(Message Queue)是进程间通信的一种机制,实际上是其内部也是采用共享内存的方式来达到进程间通信的目的。这也就意味这Message Queue有其局限性:只有处在同一台计算机中的不同进程才能使用消息队列进行通信。消息队列类似于消息列表,每个线程能够往列表里塞消息,也能从列表里读取消息。每一条消息都有三个属性:
- 1.消息优先级
- 2.消息长度
- 3.消息内容
二、消息队列的使用
消息队列的构造函数
消息队列的构造函数有三个分别是:
message_queue_t(create_only_t create_only,
const char *name,
size_type max_num_msg,
size_type max_msg_size,
const permissions &perm = permissions());
该构造函数的作用是创建一个消息队列,name用于指定消息队列的名字,max_num_msg指定创建的消息队列最多能有多少条消息同时存在,max_msg_size表示了所有的消息中最大的消息长度,最后一个参数指定了消息队列的权限,默认是0644。值得注意的是,如果已经有一个同名的消息队列存在,那么该构造函数就会抛异常。
message_queue_t(open_or_create_t open_or_create,
const char *name,
size_type max_num_msg,
size_type max_msg_size,
const permissions &perm = permissions());
第二个构造函数和的第一个构造函数大同小异,和第一个构造函数的区别是如果已经存在了一个同名消息队列就打开该消息队列,否则则创建新的消息队列。
message_queue_t(open_only_t open_only,
const char *name);
第三个构造函数仅仅是打开一个消息队列,如果没有该消息队列,则会抛出异常。
三、发送消息
在消息队列中,不管是发送消息还是接收消息都有三种模式,也分别对应了三个发送或接收的方法。
- 1:Blocking:阻塞,对于发送方来说,如果消息队列满了,则发送消息会被阻塞,直到消息队列有多余的位置来存放此条消息。而对于接收方接收数据时,如果消息队列为空,也会阻塞直到消息队列中有数据可读。
- 2:Try,非阻塞的方式,不管消息队列是空还是满都会立刻返回false。
- 3:Timed,阻塞的方式,和第一种不同的时,他会阻塞一定的时间,如果时间到了队列还是空或满的,则会返回false。
对于发送方,其三种发送的方式如下:
void send(const void *buffer, size_type buffer_size,
unsigned int priority);
bool try_send(const void *buffer, size_type buffer_size,
unsigned int priority);
bool timed_send(const void *buffer, size_type buffer_size,
unsigned int priority, const boost::posix_time::ptime& abs_time);
如上,send是阻塞的方法,try_send是非阻塞的方法,timed_send是有时间限制阻塞的方法。
参数buffer表示是消息的缓冲区,buffer_size表示buffer的大小,priority表示消息的优先级,abs_time则表示等待的时间。
但其实不管是哪种方法,都不过是对do_send方法的一层封装。
四、接收消息
接收消息同样也有三种方法,阻塞,非阻塞和有时间限制的阻塞三种。方法如下:
inline void message_queue_t<VoidPointer>::receive(void *buffer, size_type buffer_size,
size_type &recvd_size, unsigned int &priority)
{ this->do_receive(blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
template<class VoidPointer>
inline bool
message_queue_t<VoidPointer>::try_receive(void *buffer, size_type buffer_size,
size_type &recvd_size, unsigned int &priority)
{ return this->do_receive(non_blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
template<class VoidPointer>
inline bool
message_queue_t<VoidPointer>::timed_receive(void *buffer, size_type buffer_size,
size_type &recvd_size, unsigned int &priority,
const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->receive(buffer, buffer_size, recvd_size, priority);
return true;
}
return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, abs_time);
}
与发送方法类似,这三种方法也不过是对do_receive方法的一层封装。
do_receive函数原型如下:
template<class VoidPointer>
inline bool
message_queue_t<VoidPointer>::do_receive(block_t block,
void *buffer, size_type buffer_size,
size_type &recvd_size, unsigned int &priority,
const boost::posix_time::ptime &abs_time)
第一个参数block则是表示三种模式之一,buffer表示等待接收数据的缓冲区,buffer_size表示缓冲区的大小,recvd_size表示实际接收到的字节数,priority表示消息优先级,abs_time表示的是阻塞的最大时间。
do_receive的处理逻辑和do_send的处理逻辑大同小异。第一步也是对buffer_size与max_msg_size进行比较,如果buffer_size小于max_msg_size则会抛异常,这是为了保证接收方的buffer要比消息队列中最大消息长度都要大,以满足消息的正常接收。
if (buffer_size < p_hdr->m_max_msg_size) {
throw interprocess_exception(size_error);
}
第二步是对消息队列为空时的处理,和发送方对消息队列为满时的处理一致,这里不再赘述。
第三步拷贝数据也是简单的调用memcpy拷贝内存数据。
五、demo
服务端:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
using namespace boost::interprocess;
int main()
{
try {
//Erase previous message queue
message_queue::remove("message_queue");
//Create a message_queue.
message_queue mq
(create_only //only create
, "message_queue" //name
, 100 //max message number
, sizeof(int) //max message size
);
//Send 100 numbers
for (int i = 0; i < 100; ++i) {
mq.send(&i, sizeof(i), 0);
}
}
catch (interprocess_exception & ex) {
std::cout << ex.what() << std::endl;
return 1;
}
system("pause");
return 0;
}
客户端:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
using namespace boost::interprocess;
int main()
{
try {
//Open a message queue.
message_queue mq
(open_only //only create
, "message_queue" //name
);
unsigned int priority;
message_queue::size_type recvd_size;
//Receive 100 numbers
for (int i = 0; i < 200; ++i)
{
int number;
mq.receive(&number, sizeof(number), recvd_size, priority);
printf("I:%d Rec:%d\n", i, number);
if (number != i || recvd_size != sizeof(number))
return 1;
}
}
catch (interprocess_exception & ex) {
message_queue::remove("message_queue");
std::cout << ex.what() << std::endl;
return 1;
}
message_queue::remove("message_queue");
system("pause");
return 0;
}
结果:
————————————————
参考链接:https://blog.csdn.net/weixin_43055404/article/details/111885041