ZeroMQ_06 发布-订阅代理服务
我们经常会需要将发布-订阅模式扩充到不同类型的网络中。比如说,有一组订阅者是在外网上的,我们想用广播的方式发布消息给内网的订阅者,而用TCP协议发送给外网订阅者。
我们要做的就是写一个简单的代理服务装置,在发布者和外网订阅者之间搭起桥梁。这个装置有两个端点,一端连接内网上的发布者,另一端连接到外网上。它会从发布者处接收订阅的消息,并转发给外网上的订阅者们。
server
#include "../zhelpers.h" int main (void) { // Prepare our context and publisher void *context = zmq_ctx_new (); void *publisher = zmq_socket (context, ZMQ_PUB); int rc = zmq_bind (publisher, "tcp://*:5557"); assert (rc == 0); // Initialize random number generator srandom ((unsigned) time (NULL)); while (1) { // Get values that will fool the boss int zipcode, temperature, relhumidity; zipcode = randof (100000); temperature = randof (215) - 80; relhumidity = randof (50) + 10; // Send message to all subscribers char update [20]; sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity); printf("send message : %s\n", update); s_send (publisher, update); } zmq_close (publisher); zmq_ctx_destroy (context); return 0; }
proxy
#include "../zhelpers.h" int main (void) { void *context = zmq_ctx_new (); // This is where the weather server sits void *frontend = zmq_socket (context, ZMQ_XSUB); int rc =zmq_connect (frontend, "tcp://localhost:5557"); assert (rc == 0); // This is our public endpoint for subscribers void *backend = zmq_socket (context, ZMQ_XPUB); rc = zmq_bind (backend, "tcp://127.0.0.1:8111"); assert (rc == 0); // Run the proxy until the user interrupts us printf("zmq_proxy...begin \n"); zmq_proxy (frontend, backend, NULL); printf("zmq_proxy...end \n"); zmq_close (frontend); zmq_close (backend); zmq_ctx_destroy (context); return 0; }
client
#include "../zhelpers.h" int main (int argc, char *argv []) { // Socket to talk to server printf ("Collecting updates from weather server...\n"); void *context = zmq_ctx_new (); void *subscriber = zmq_socket (context, ZMQ_SUB); int rc = zmq_connect (subscriber, "tcp://localhost:8111"); assert (rc == 0); // Subscribe to zipcode, default is NYC, 10001 const char *filter = "1"; rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, filter, strlen (filter)); assert (rc == 0); // Process 100 updates int update_nbr; long total_temp = 0; for (update_nbr = 0; update_nbr < 100; update_nbr++) { char *string = s_recv (subscriber); printf("recv message : %s\n", string); int zipcode, temperature, relhumidity; sscanf (string, "%d %d %d", &zipcode, &temperature, &relhumidity); total_temp += temperature; free (string); } printf ("Average temperature for zipcode '%s' was %dF\n", filter, (int) (total_temp / update_nbr)); zmq_close (subscriber); zmq_ctx_destroy (context); return 0; }
我们称这个装置为代理,因为它既是订阅者,又是发布者。这就意味着,添加该装置时不需要更改其他程序的代码,只需让外网订阅者知道新的网络地址即可。
out
// server send message : 69513 126 18 send message : 81998 2 52 send message : 89759 55 11 send message : 46156 21 21 send message : 99744 -27 59 send message : 03687 56 26 send message : 87373 -9 39 send message : 03237 -42 29 send message : 81249 119 17 send message : 13946 -23 58 send message : 11892 126 56 send message : 28408 88 25 send message : 13726 66 57 send message : 15999 -50 30 send message : 39683 -51 43 send message : 38166 -43 25 send message : 71268 -70 41 send message : 29271 -63 50 // client recv message : 10623 -4 22 recv message : 17512 82 27 recv message : 16574 -75 39 recv message : 12919 -31 39 recv message : 19449 93 45 recv message : 16524 19 23 recv message : 15305 63 54 recv message : 10077 -49 37 recv message : 14690 -1 22 Average temperature for zipcode '1' was 17F