一、背景
二、相关知识
2.1 ZMQ_PUB
ZMQ_PUB A socket of type ZMQ_PUB is used by a publisher to distribute data. Messages sent are distributed in a fan out fashion to all connected peers. The zmq_recv(3) function is not implemented for this socket type. When a ZMQ_PUB socket enters the mute state due to having reached the high water mark for a subscriber, then any messages that would be sent to the subscriber in question shall instead be dropped until the mute state ends. The zmq_send() function shall never block for this socket type.
ZMQ_PUB为发布端socket类型,用于消息分发,消息以扇出的方式分发到各个连接端上。该socket类型仅支持zmq_send进行发送,不支持zmq_recv()。注意当订阅者处理速度慢的时候,需要在PUB设置合适的高水位HWM来保证消息不会丢失。
2.2 ZMQ_SUB
ZMQ_SUB A socket of type ZMQ_SUB is used by a subscriber to subscribe to data distributed by a publisher. Initially a ZMQ_SUB socket is not subscribed to any messages, use the ZMQ_SUBSCRIBE option of zmq_setsockopt(3) to specify which messages to subscribe to. The zmq_send() function is not implemented for this socket type.
2.3 使用方法
使用方法为一个PUB对应多个SUB,如图所示:
三、实现
Publisher代码如下,绑定在127.0.0.1:5443 上进行监听
void test_pub(void *ctx, int times) { int ret = 0, ix = 0; char id[16] = {0}; char request[1024]; void *sock = zmq_socket(ctx, ZMQ_PUB); assert(sock); s_set_id_ex(sock, id, sizeof(id)); ret = zmq_bind(sock, "tcp://127.0.0.1:5443"); assert(ret == 0); LOGN("Pub %s start\n", id); for (ix = 0; ix < times; ix++) { snprintf(request, sizeof(request), "Data-%03s-%03d", id, ix); s_send(sock, request); LOGN("Pub %s send: %s\n", id, request); usleep(300 * 1000); } LOGN("Pub %s stop\n", id); zmq_close(sock); }
Subscriber则进行地址连接,进行接收:
int test_sub(void *ctx) { int ret = 0, cnt = 0; char id[16] = {0}; char request[1024]; void *sock = zmq_socket(ctx, ZMQ_SUB); assert(sock); s_set_id_ex(sock, id, sizeof(id)); ret = zmq_connect(sock, "tcp://127.0.0.1:5443"); assert(ret == 0); ret = zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0); assert(ret == 0); LOGN("Sub %s start\n", id); while (++cnt) { s_recv(sock, request); LOGN("Sub %s recv: %s\n", id, request); usleep(300 * 1000); } LOGN("Sub %s stop\n", id); zmq_close(sock); }
主函数入口:
int main(int argc, char *argv[]) { void *ctx = zmq_ctx_new(); assert(ctx); srandom(time(NULL)); if (argc > 1) { test_pub(ctx, atoi(argv[1])); } else { test_sub(ctx); } zmq_ctx_destroy(ctx); exit(EXIT_SUCCESS); }
开启2个Subscriber、1个Publisher,执行结果:
Subscriber#1、Subscriber#2 先启动后阻塞住,开启Publisher后才收到消息:
./pubsub [ 1528395731.593 ]: Sub 0034 start [ 1528395745.306 ]: Sub 0034 recv: Data-00B9-001 [ 1528395745.607 ]: Sub 0034 recv: Data-00B9-002 [ 1528395745.907 ]: Sub 0034 recv: Data-00B9-003 [ 1528395746.209 ]: Sub 0034 recv: Data-00B9-004 [ 1528395746.509 ]: Sub 0034 recv: Data-00B9-005 [ 1528395746.810 ]: Sub 0034 recv: Data-00B9-006 [ 1528395747.111 ]: Sub 0034 recv: Data-00B9-007 [ 1528395747.413 ]: Sub 0034 recv: Data-00B9-008 [ 1528395747.714 ]: Sub 0034 recv: Data-00B9-009
./pubsub [ 1528395738.672 ]: Sub 00B7 start [ 1528395745.306 ]: Sub 00B7 recv: Data-00B9-001 [ 1528395745.607 ]: Sub 00B7 recv: Data-00B9-002 [ 1528395745.907 ]: Sub 00B7 recv: Data-00B9-003 [ 1528395746.209 ]: Sub 00B7 recv: Data-00B9-004 [ 1528395746.509 ]: Sub 00B7 recv: Data-00B9-005 [ 1528395746.810 ]: Sub 00B7 recv: Data-00B9-006 [ 1528395747.111 ]: Sub 00B7 recv: Data-00B9-007 [ 1528395747.413 ]: Sub 00B7 recv: Data-00B9-008 [ 1528395747.714 ]: Sub 00B7 recv: Data-00B9-009
Publisher:
./pubsub 10 [ 1528395745.004 ]: Pub 00B9 start [ 1528395745.004 ]: Pub 00B9 send: Data-00B9-000 [ 1528395745.306 ]: Pub 00B9 send: Data-00B9-001 [ 1528395745.606 ]: Pub 00B9 send: Data-00B9-002 [ 1528395745.907 ]: Pub 00B9 send: Data-00B9-003 [ 1528395746.208 ]: Pub 00B9 send: Data-00B9-004 [ 1528395746.509 ]: Pub 00B9 send: Data-00B9-005 [ 1528395746.809 ]: Pub 00B9 send: Data-00B9-006 [ 1528395747.111 ]: Pub 00B9 send: Data-00B9-007 [ 1528395747.412 ]: Pub 00B9 send: Data-00B9-008 [ 1528395747.714 ]: Pub 00B9 send: Data-00B9-009 [ 1528395748.014 ]: Pub 00B9 stop
netstat -anpt|grep pubsub tcp 0 0 127.0.0.1:5443 0.0.0.0:* LISTEN 31141/pubsub tcp 0 0 127.0.0.1:36680 127.0.0.1:5443 ESTABLISHED 31074/pubsub tcp 0 0 127.0.0.1:36678 127.0.0.1:5443 ESTABLISHED 31071/pubsub tcp 0 0 127.0.0.1:5443 127.0.0.1:36680 ESTABLISHED 31141/pubsub tcp 0 0 127.0.0.1:5443 127.0.0.1:36678 ESTABLISHED 31141/pubsub期间netstat查看连接状态,发现Publisher启动后,两个Subscriber才建立起socket连接;
四、结论
参考文章:
文章来源: Linux下使用ZMQ实践“发布-订阅”模型