使用版本4.2.5,因社区介绍说udp的还不成熟,所以发布订阅用tcp的。一般使用场景是跨机器的,为了消除不同机器之间时间差,采用了互为发布订阅者。发布者程序在主线程中作为发布者定时发送数据,每条数据发完之后sleep的目的是:订阅者没法那么快处理,会丢数据。订阅者收到数据后,在子线程中把数据再发送回去。发布者通过子线程来接收订阅者返回的数据。通过接收时间-发送时间=2倍的单向延迟。
发布者pub.c
#include "zmq.h"
#include <iostream>
#include <string.h>
#include <assert.h>
#include <stdlib.h> /* atoi */
#include <stdio.h>
#include <thread> // std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
int i = 0;
char subip[30] = {0};
uint64_t tback = 0;
static inline long get_nano_second()
{
timespec ts = {0};
clock_gettime(CLOCK_MONOTONIC, &ts);
return (long)(1000000000UL * ts.tv_sec + ts.tv_nsec);
}
void foo()
{
// do stuff...
void* context = zmq_ctx_new();
assert(context != NULL);
void* subscriber = zmq_socket(context, ZMQ_SUB);
assert(subscriber != NULL);
int ret = zmq_connect(subscriber, subip);
assert(ret == 0);
ret = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
assert(ret == 0);
while(1)
{
char szBuf[1024] = {0};
ret = zmq_recv(subscriber, szBuf, sizeof(szBuf) - 1, 0);
if (ret > 0)
{
printf("i=%d %s\n", i, szBuf);
tback = get_nano_second();
break;
}
else
printf("zmq_recv=%d\n", ret);
}
zmq_close(subscriber);
zmq_ctx_destroy(context);
}
int main(int argc, char *argv[])
{
int major, minor, patch;
zmq_version(&major, &minor, &patch);
printf("zmq version: %d.%d.%d\n", major, minor, patch);
int n = 10000, k = 50;
char sip[30] = {0};
if (argc > 1) n = atoi(argv[1]);
if (argc > 2) k = atoi(argv[2]);
if (argc > 3)
strcpy(sip, argv[3]);
else
strcpy(sip, "tcp://192.168.67.144:5555");
if (argc > 4)
strcpy(subip, argv[4]);
void* context = zmq_ctx_new();
/* Create a ZMQ_PUB socket */
void *socket = zmq_socket (context, ZMQ_PUB);
assert (socket);
/* Bind it to a in-process transport with the address 'my_publisher' */
int rc = zmq_bind (socket, sip); assert (rc == 0);
std::thread first(foo);
getchar();
uint64_t t1 = 0, t2 = 0, tk = 0;
int ret = 0;
while (true) {
++i;
if (i == 1) t1 = get_nano_second();
if (i == k) tk = get_nano_second();
char szBuf[1024] = {0};
snprintf(szBuf, sizeof(szBuf), "server i=%d", i);
ret = zmq_send(socket, szBuf, strlen(szBuf) + 1, 0);
printf("%d\n", i);
if (i >= n) break;
std::this_thread::sleep_for(std::chrono::microseconds(2));
}
t2 = get_nano_second();
first.join(); // pauses until first finishes
printf("t1=%ld\t t2=%ld\t tk=%ld tback=%ld t2-t1=%ld\n", t1, t2, tk, tback, tback-tk);
zmq_close(socket);
zmq_ctx_destroy(context);
return 0;
}
订阅者sub.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "zmq.h"
#include <stdlib.h> /* atoi */
#include <string.h>
#include <iostream>
int main(int argc, char *argv[])
{
void* context = zmq_ctx_new();
assert(context != NULL);
void* subscriber = zmq_socket(context, ZMQ_SUB);
assert(subscriber != NULL);
int n = 10000, k = 50;
char sip[30] = {0};
char pubip[30] = {0};
if (argc > 1) n = atoi(argv[1]);
if (argc > 2) k = atoi(argv[2]);
if (argc > 3)
strcpy(sip, argv[3]);
else
strcpy(sip, "tcp://192.168.67.144:5555");
if (argc > 4)
strcpy(pubip, argv[4]);
int ret = zmq_connect(subscriber, sip);
assert(ret == 0);
ret = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
assert(ret == 0);
//---
void* context_pub = zmq_ctx_new();
/* Create a ZMQ_PUB socket */
void *socket_pub = zmq_socket(context_pub, ZMQ_PUB);
assert(socket_pub);
int rc_pub = zmq_bind(socket_pub, pubip); assert(rc_pub == 0);
int i = 0;
while(1)
{
++i;
char szBuf[1024] = {0};
ret = zmq_recv(subscriber, szBuf, sizeof(szBuf) - 1, 0);
if (ret > 0)
{
printf("i=%d %s\n", i, szBuf);
}
else
printf("zmq_recv=%d\n", ret);
if (i == k)
zmq_send(socket_pub, szBuf, strlen(szBuf) + 1, 0);
if (i >= n) break;
}
zmq_close(subscriber);
zmq_ctx_destroy(context);
zmq_close(socket_pub);
zmq_ctx_destroy(context_pub);
return 0;
}
编译:
g++ -std=c++11 pub.c -L./ -lzmq -lpthread -o pub
g++ -std=c++11 sub.cpp -L./ -lzmq -lpthread -o sub
分别放到两台机器运行
./pub 20000 19000 tcp://192.168.1.7:5550 tcp://192.168.1.8:5560
./sub 20000 19000 tcp://192.168.1.7:5550 tcp://192.168.1.8:5560
一个来回的耗时350us左右,单趟约等于175us。