在之前的示例中,主程序的循环体内会做以下几件事:
1、等待套接字的消息。
2、处理消息。
3、返回第一步。
如果我们想要读取多个套接字中的消息呢?最简单的方法是将套接字连接到多个端点上,让ZMQ使用公平队列的机制来接受消息。如果不同端点上的套接字类型是一致的,那可以使用这种方法。但是,如果一个套接字的类型是PULL,另一个是PUB怎么办?如果现在开始混用套接字类型,那将来就没有可靠性可言了。
正确的方法应该是使用zmq_poll()函数。更好的方法是将zmq_poll()包装成一个框架,编写一个事件驱动的反应器,但这个就比较复杂了,我们这里暂不讨论。
我们先不使用zmq_poll(),而用NOBLOCK(非阻塞)的方式来实现从多个套接字读取消息的功能。下面将气象信息服务和并行处理这两个示例结合起来:
msreader: Multiple socket reader in C
#include "zhelpers.h"int main (void)
{// 准备上下文和套接字void *context = zmq_init (1);// 连接至任务分发器void *receiver = zmq_socket (context, ZMQ_PULL);zmq_connect (receiver, "tcp://localhost:5557");// 连接至天气服务void *subscriber = zmq_socket (context, ZMQ_SUB);zmq_connect (subscriber, "tcp://localhost:5556");zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, "10001 ", 6);// 处理从两个套接字中接收到的消息// 这里我们会优先处理从任务分发器接收到的消息while (1) {// 处理等待中的任务int rc;for (rc = 0; !rc; ) {zmq_msg_t task;zmq_msg_init (&task);if ((rc = zmq_recv (receiver, &task, ZMQ_NOBLOCK)) == 0) {// 处理任务}zmq_msg_close (&task);}// 处理等待中的气象更新for (rc = 0; !rc; ) {zmq_msg_t update;zmq_msg_init (&update);if ((rc = zmq_recv (subscriber, &update, ZMQ_NOBLOCK)) == 0) {// 处理气象更新}zmq_msg_close (&update);}// 没有消息,等待1毫秒s_sleep (1);}// 程序不会运行到这里,但还是做正确的退出清理工作zmq_close (receiver);zmq_close (subscriber);zmq_term (context);return 0;
}
这种方式的缺点之一是,在收到第一条消息之前会有1毫秒的延迟,这在高压力的程序中还是会构成问题的。此外,你还需要翻阅诸如nanosleep()的函数,不会造成循环次数的激增。
示例中将任务分发器的优先级提升了,你可以做一个改进,轮流处理消息,正如ZMQ内部做的公平队列机制一样。
下面,让我们看看如何用zmq_poll()来实现同样的功能:
mspoller: Multiple socket poller in C
#include "zhelpers.h"int main (void)
{void *context = zmq_init (1);// 连接任务分发器void *receiver = zmq_socket (context, ZMQ_PULL);zmq_connect (receiver, "tcp://localhost:5557");// 连接气象更新服务void *subscriber = zmq_socket (context, ZMQ_SUB);zmq_connect (subscriber, "tcp://localhost:5556");zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, "10001 ", 6);// 初始化轮询对象zmq_pollitem_t items [] = {{ receiver, 0, ZMQ_POLLIN, 0 },{ subscriber, 0, ZMQ_POLLIN, 0 }};// 处理来自两个套接字的消息while (1) {zmq_msg_t message;zmq_poll (items, 2, -1);if (items [0].revents & ZMQ_POLLIN) {zmq_msg_init (&message);zmq_recv (receiver, &message, 0);// 处理任务zmq_msg_close (&message);}if (items [1].revents & ZMQ_POLLIN) {zmq_msg_init (&message);zmq_recv (subscriber, &message, 0);// 处理气象更新zmq_msg_close (&message);}}// 程序不会运行到这儿zmq_close (receiver);zmq_close (subscriber);zmq_term (context);return 0;
}