前言

在这里插入图片描述

ZeroMQ是个类似于 Socket 的一系列接口,他跟 Socket 的区别是:普通的 socket 是端到端的(1:1的关系),而 ZMQ 却是可以N:M 的关系,人们对 BSD 套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而 ZMQ 屏蔽了这些细节,让你的网络编程更为简单。ZMQ 用于 node 与 node 间的通信,node 可以是主机或者是进程。
源码地址:https://download.csdn.net/download/VOR234/92218737
ZMQ有三种通信模式:分别为请求应答模式、发布订阅模式以及推拉模式,本项目拟采用发布订阅模式,主要是考虑到本项目中的协同建图的这种多对一的模式,适用于单项数据的传递。在同两台设备上运行的不同进程之间(或线程间)进行数据交互时,传统的TCP、UDP断开连接后不能自动重连,但开发与维护成本较高。

ZeroMQ(ZMQ) 提供了一种轻量、快速、跨语言的通信机制,支持:

  • 发布-订阅(PUB/SUB)
  • 请求-应答(REQ/REP)
  • 推送-拉取(PUSH/PULL)
  • 配对(PAIR)

本文将展示在同一台设备上、不同进程间的三种 ZMQ 通信模型实现:

  1. 🔁 发布订阅模式(Pub/Sub)
  2. 🧩 双向发布订阅(两个节点互发)
  3. 🔗 配对模式(PAIR 双向通信)

相关学习:
【配置VS2022和Ubuntu22.04下的ZeroMQ C++安装环境&两设备双向通讯测试案例】
【同一设备进程间 ZeroMQ 两节点双向通讯测试案例】

1.VS2022下的ZeroMQ C++安装环境

1. 1安装 ZeroMQ

  1. 下载 ZeroMQ 预编译库

在这里插入图片描述

  • 解压到项目目录,主要是两个DLL和一个LIB有用
    在这里插入图片描述

1.2 VS2022 项目配置步骤

然后新建C++项目Zero_server,将上面解压的zmq.h添加为头文件

在这里插入图片描述
接下来的三个demo我会一一分解,现在需要

  1. 项目属性配置

    • 链接器 → 输入 → 附加依赖项:添加 libzmq-mt-4_3_4.lib
      在这里插入图片描述
  2. 将 DLL 文件复制到输出目录

    • libzmq-mt-4_3_4.dlllibsodium.dll复制到 DebugRelease 目录
      在这里插入图片描述

这个版本使用 C 风格的 ZeroMQ API,避免了 C++ 头文件的问题,应该可以正常编译运行。

2.Ubuntu22.04下的ZeroMQ C++安装环境

参考教程见:https://github.com/zeromq/cppzmq
在这里插入图片描述

2.1下载源码

如果ubuntu系统github网络环境不好,推荐下面这种方法,在win环境下下载这两个文件,然后scp复制到目标主机

git clone https://github.com/zeromq/cppzmq.git
git clone https://github.com/zeromq/libzmq.git
scp -r D:\中国一重\项目文档\libzmq Tronlong@192.168.170.76:/home/Tronlong/mmcblk0p8/project_code/project
scp -r D:\中国一重\项目文档\cppzmq Tronlong@192.168.170.76:/home/Tronlong/mmcblk0p8/project_code/project

在这里插入图片描述
在这里插入图片描述

2.2安装libzmq库

Build steps:

  1. Build libzmq via cmake. This does an out of source build and installs the build files
    • git clone https://github.com/zeromq/libzmq.git
    • cd libzmq
    • mkdir build
    • cd build
    • cmake ..
    • sudo make -j4 install
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project$ cd libzmq/
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq$ mkdir build
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq$ cd build
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq/build$ cmake ..
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Detected ZMQ Version - 4.3.6
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2")
-- Performing Test COMPILER_SUPPORTS_CXX11
-- Performing Test COMPILER_SUPPORTS_CXX11 - Success
-- Performing Test COMPILER_SUPPORTS_C11
-- Performing Test COMPILER_SUPPORTS_C11 - Success
-- Performing Test CXX_HAS_TAUT_WARNING
-- Performing Test CXX_HAS_TAUT_WARNING - Success
-- Performing Test CC_HAS_TAUT_WARNING
-- Performing Test CC_HAS_TAUT_WARNING - Success
-- Building draft classes and methods
-- Using radix tree implementation to manage subscriptions
-- Enable WebSocket transport
-- Could NOT find GnuTLS (missing: GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR) (Required is at least version "3.6.7")
CMake Warning at CMakeLists.txt:215 (message):
  No WSS support, you may want to install GnuTLS and run cmake again


-- Using builtin sha1
-- Checking for module 'libbsd'
--   Found libbsd, version 0.11.5
-- Using libbsd
-- Looking for strlcpy
-- Looking for strlcpy - not found
-- CURVE security is disabled
-- Looking for kqueue
-- Looking for kqueue - not found
-- Looking for epoll_create
-- Looking for epoll_create - found
-- Looking for epoll_create1
-- Looking for epoll_create1 - found
-- Using polling method in I/O threads: epoll
-- Using polling method in zmq_poll(er)_* API: poll
-- Looking for pselect
-- Looking for pselect - found
-- Using 64 bytes alignment for lock-free data structures
-- Looking for posix_memalign
-- Looking for posix_memalign - found
-- Looking for include file windows.h
-- Looking for include file windows.h - not found
-- Looking for include file condition_variable
-- Looking for include file condition_variable - found
-- Using condition_variable_t implementation: stl11
-- Looking for include file ifaddrs.h
-- Looking for include file ifaddrs.h - found
-- Looking for include file sys/uio.h
-- Looking for include file sys/uio.h - found
-- Looking for include file sys/eventfd.h
-- Looking for include file sys/eventfd.h - found
-- Checking whether EFD_CLOEXEC is supported
-- Performing Test ZMQ_HAVE_EVENTFD_CLOEXEC
-- Performing Test ZMQ_HAVE_EVENTFD_CLOEXEC - Success
-- Looking for if_nametoindex
-- Looking for if_nametoindex - found
-- Looking for SO_PEERCRED
-- Looking for SO_PEERCRED - found
-- Looking for LOCAL_PEERCRED
-- Looking for LOCAL_PEERCRED - not found
-- Looking for SO_BUSY_POLL
-- Looking for SO_BUSY_POLL - found
-- Looking for clock_gettime
-- Looking for clock_gettime - found
-- Looking for fork
-- Looking for fork - found
-- Looking for gethrtime
-- Looking for gethrtime - not found
-- Looking for mkdtemp
-- Looking for mkdtemp - found
-- Looking for accept4
-- Looking for accept4 - found
-- Looking for strnlen
-- Looking for strnlen - found
-- Performing Test HAVE_FLAG_-Wall
-- Performing Test HAVE_FLAG_-Wall - Failed
-- Performing Test HAVE_FLAG_-Wextra
-- Performing Test HAVE_FLAG_-Wextra - Failed
-- Performing Test HAVE_FLAG_-Wno-long-long
-- Performing Test HAVE_FLAG_-Wno-long-long - Failed
-- Performing Test HAVE_FLAG_-Wno-uninitialized
-- Performing Test HAVE_FLAG_-Wno-uninitialized - Failed
-- Performing Test HAVE_FLAG_-pedantic
-- Performing Test HAVE_FLAG_-pedantic - Failed
-- Checking whether noexcept is supported
-- Performing Test ZMQ_HAVE_NOEXCEPT
-- Performing Test ZMQ_HAVE_NOEXCEPT - Success
-- Checking pthread_setname signature
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_1
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_1 - Failed
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_2
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_2 - Success
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_3
-- Performing Test ZMQ_HAVE_PTHREAD_SETNAME_3 - Failed
-- Performing Test ZMQ_HAVE_PTHREAD_SET_NAME
-- Performing Test ZMQ_HAVE_PTHREAD_SET_NAME - Failed
-- Checking pthread_setaffinity signature
-- Performing Test ZMQ_HAVE_PTHREAD_SET_AFFINITY
-- Performing Test ZMQ_HAVE_PTHREAD_SET_AFFINITY - Success
-- Checking whether SOCK_CLOEXEC is supported
-- Performing Test ZMQ_HAVE_SOCK_CLOEXEC
-- Performing Test ZMQ_HAVE_SOCK_CLOEXEC - Success
-- Checking whether O_CLOEXEC is supported
-- Performing Test ZMQ_HAVE_O_CLOEXEC
-- Performing Test ZMQ_HAVE_O_CLOEXEC - Success
-- Checking whether SO_BINDTODEVICE is supported
-- Performing Test ZMQ_HAVE_SO_BINDTODEVICE
-- Performing Test ZMQ_HAVE_SO_BINDTODEVICE - Success
-- Checking whether SO_KEEPALIVE is supported
-- Performing Test ZMQ_HAVE_SO_KEEPALIVE
-- Performing Test ZMQ_HAVE_SO_KEEPALIVE - Success
-- Checking whether SO_PRIORITY is supported
-- Performing Test ZMQ_HAVE_SO_PRIORITY
-- Performing Test ZMQ_HAVE_SO_PRIORITY - Success
-- Checking whether TCP_KEEPCNT is supported
-- Performing Test ZMQ_HAVE_TCP_KEEPCNT
-- Performing Test ZMQ_HAVE_TCP_KEEPCNT - Success
-- Checking whether TCP_KEEPIDLE is supported
-- Performing Test ZMQ_HAVE_TCP_KEEPIDLE
-- Performing Test ZMQ_HAVE_TCP_KEEPIDLE - Success
-- Checking whether TCP_KEEPINTVL is supported
-- Performing Test ZMQ_HAVE_TCP_KEEPINTVL
-- Performing Test ZMQ_HAVE_TCP_KEEPINTVL - Success
-- Checking whether TCP_KEEPALIVE is supported
-- Performing Test ZMQ_HAVE_TCP_KEEPALIVE
-- Performing Test ZMQ_HAVE_TCP_KEEPALIVE - Failed
-- Checking whether TIPC is supported
-- Performing Test ZMQ_HAVE_TIPC
-- Performing Test ZMQ_HAVE_TIPC - Success
-- Checking whether getrandom is supported
-- Performing Test ZMQ_HAVE_GETRANDOM
-- Performing Test ZMQ_HAVE_GETRANDOM - Success
-- Could NOT find AsciiDoctor (missing: ASCIIDOCTOR_EXECUTABLE) 
CMake Warning (dev) at tests/CMakeLists.txt:346 (message):
  Test 'test_bind_stream_fuzzer' is not known to CTest.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at tests/CMakeLists.txt:346 (message):
  Test 'test_bind_ws_fuzzer' is not known to CTest.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at tests/CMakeLists.txt:346 (message):
  Test 'test_connect_stream_fuzzer' is not known to CTest.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at tests/CMakeLists.txt:346 (message):
  Test 'test_connect_ws_fuzzer' is not known to CTest.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at tests/CMakeLists.txt:346 (message):
  Test 'test_socket_options_fuzzer' is not known to CTest.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done (12.5s)
-- Generating done (1.2s)
-- Build files have been written to: /home/Tronlong/mmcblk0p8/project_code/project/libzmq/build
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq/build$ sudo make -j4 install
[  0%] Building C object tests/CMakeFiles/unity.dir/__/external/unity/unity.c.o
[  0%] Building CXX object CMakeFiles/objects.dir/src/ws_address.cpp.o
[  0%] Building CXX object CMakeFiles/objects.dir/src/ws_connecter.cpp.o
[  1%] Building CXX object CMakeFiles/objects.dir/src/ws_decoder.cpp.o
[  2%] Linking C static library ../lib/libunity.a
[  2%] Built target unity
[  2%] Building CXX object CMakeFiles/objects.dir/src/ws_encoder.cpp.o
[  2%] Building CXX object CMakeFiles/objects.dir/src/ws_engine.cpp.o
[  2%] Building CXX object CMakeFiles/objects.dir/src/ws_listener.cpp.o
[  3%] Building C object CMakeFiles/objects.dir/external/sha1/sha1.c.o
[  3%] Building CXX object CMakeFiles/objects.dir/src/precompiled.cpp.o
[  3%] Building CXX object CMakeFiles/objects.dir/src/address.cpp.o
[  3%] Building CXX object CMakeFiles/objects.dir/src/channel.cpp.o
[  4%] Building CXX object CMakeFiles/objects.dir/src/client.cpp.o
[  4%] Building CXX object CMakeFiles/objects.dir/src/clock.cpp.o
[  4%] Building CXX object CMakeFiles/objects.dir/src/ctx.cpp.o
[  4%] Building CXX object CMakeFiles/objects.dir/src/curve_mechanism_base.cpp.o
[  5%] Building CXX object CMakeFiles/objects.dir/src/curve_client.cpp.o
[  5%] Building CXX object CMakeFiles/objects.dir/src/curve_server.cpp.o
[  5%] Building CXX object CMakeFiles/objects.dir/src/dealer.cpp.o
[  5%] Building CXX object CMakeFiles/objects.dir/src/devpoll.cpp.o
[  6%] Building CXX object CMakeFiles/objects.dir/src/dgram.cpp.o
[  6%] Building CXX object CMakeFiles/objects.dir/src/dist.cpp.o
[  6%] Building CXX object CMakeFiles/objects.dir/src/endpoint.cpp.o
[  6%] Building CXX object CMakeFiles/objects.dir/src/epoll.cpp.o
[  7%] Building CXX object CMakeFiles/objects.dir/src/err.cpp.o
[  7%] Building CXX object CMakeFiles/objects.dir/src/fq.cpp.o
[  7%] Building CXX object CMakeFiles/objects.dir/src/io_object.cpp.o
[  7%] Building CXX object CMakeFiles/objects.dir/src/io_thread.cpp.o
[  8%] Building CXX object CMakeFiles/objects.dir/src/ip.cpp.o
[  8%] Building CXX object CMakeFiles/objects.dir/src/ipc_address.cpp.o
[  8%] Building CXX object CMakeFiles/objects.dir/src/ipc_connecter.cpp.o
[  8%] Building CXX object CMakeFiles/objects.dir/src/ipc_listener.cpp.o
[  9%] Building CXX object CMakeFiles/objects.dir/src/kqueue.cpp.o
[  9%] Building CXX object CMakeFiles/objects.dir/src/lb.cpp.o
[  9%] Building CXX object CMakeFiles/objects.dir/src/mailbox.cpp.o
[  9%] Building CXX object CMakeFiles/objects.dir/src/mailbox_safe.cpp.o
[ 10%] Building CXX object CMakeFiles/objects.dir/src/mechanism.cpp.o
[ 10%] Building CXX object CMakeFiles/objects.dir/src/mechanism_base.cpp.o
[ 10%] Building CXX object CMakeFiles/objects.dir/src/metadata.cpp.o
[ 10%] Building CXX object CMakeFiles/objects.dir/src/msg.cpp.o
[ 11%] Building CXX object CMakeFiles/objects.dir/src/mtrie.cpp.o
[ 11%] Building CXX object CMakeFiles/objects.dir/src/norm_engine.cpp.o
[ 11%] Building CXX object CMakeFiles/objects.dir/src/object.cpp.o
[ 11%] Building CXX object CMakeFiles/objects.dir/src/options.cpp.o
[ 12%] Building CXX object CMakeFiles/objects.dir/src/own.cpp.o
[ 12%] Building CXX object CMakeFiles/objects.dir/src/null_mechanism.cpp.o
[ 12%] Building CXX object CMakeFiles/objects.dir/src/pair.cpp.o
[ 12%] Building CXX object CMakeFiles/objects.dir/src/peer.cpp.o
[ 12%] Building CXX object CMakeFiles/objects.dir/src/pgm_receiver.cpp.o
[ 13%] Building CXX object CMakeFiles/objects.dir/src/pgm_sender.cpp.o
[ 13%] Building CXX object CMakeFiles/objects.dir/src/pgm_socket.cpp.o
[ 13%] Building CXX object CMakeFiles/objects.dir/src/pipe.cpp.o
[ 13%] Building CXX object CMakeFiles/objects.dir/src/plain_client.cpp.o
[ 14%] Building CXX object CMakeFiles/objects.dir/src/plain_server.cpp.o
[ 14%] Building CXX object CMakeFiles/objects.dir/src/poll.cpp.o
[ 14%] Building CXX object CMakeFiles/objects.dir/src/poller_base.cpp.o
[ 14%] Building CXX object CMakeFiles/objects.dir/src/polling_util.cpp.o
[ 15%] Building CXX object CMakeFiles/objects.dir/src/pollset.cpp.o
[ 15%] Building CXX object CMakeFiles/objects.dir/src/proxy.cpp.o
[ 15%] Building CXX object CMakeFiles/objects.dir/src/pub.cpp.o
[ 15%] Building CXX object CMakeFiles/objects.dir/src/pull.cpp.o
[ 16%] Building CXX object CMakeFiles/objects.dir/src/push.cpp.o
[ 16%] Building CXX object CMakeFiles/objects.dir/src/random.cpp.o
[ 16%] Building CXX object CMakeFiles/objects.dir/src/raw_encoder.cpp.o
[ 16%] Building CXX object CMakeFiles/objects.dir/src/raw_decoder.cpp.o
[ 17%] Building CXX object CMakeFiles/objects.dir/src/raw_engine.cpp.o
[ 17%] Building CXX object CMakeFiles/objects.dir/src/reaper.cpp.o
[ 17%] Building CXX object CMakeFiles/objects.dir/src/rep.cpp.o
[ 17%] Building CXX object CMakeFiles/objects.dir/src/req.cpp.o
[ 18%] Building CXX object CMakeFiles/objects.dir/src/router.cpp.o
[ 18%] Building CXX object CMakeFiles/objects.dir/src/select.cpp.o
[ 18%] Building CXX object CMakeFiles/objects.dir/src/server.cpp.o
[ 18%] Building CXX object CMakeFiles/objects.dir/src/session_base.cpp.o
[ 19%] Building CXX object CMakeFiles/objects.dir/src/signaler.cpp.o
[ 19%] Building CXX object CMakeFiles/objects.dir/src/socket_base.cpp.o
[ 19%] Building CXX object CMakeFiles/objects.dir/src/socks.cpp.o
[ 19%] Building CXX object CMakeFiles/objects.dir/src/socks_connecter.cpp.o
[ 20%] Building CXX object CMakeFiles/objects.dir/src/stream.cpp.o
[ 20%] Building CXX object CMakeFiles/objects.dir/src/stream_engine_base.cpp.o
[ 20%] Building CXX object CMakeFiles/objects.dir/src/sub.cpp.o
[ 20%] Building CXX object CMakeFiles/objects.dir/src/tcp.cpp.o
[ 21%] Building CXX object CMakeFiles/objects.dir/src/tcp_address.cpp.o
[ 21%] Building CXX object CMakeFiles/objects.dir/src/tcp_connecter.cpp.o
[ 21%] Building CXX object CMakeFiles/objects.dir/src/tcp_listener.cpp.o
[ 21%] Building CXX object CMakeFiles/objects.dir/src/thread.cpp.o
[ 22%] Building CXX object CMakeFiles/objects.dir/src/trie.cpp.o
[ 22%] Building CXX object CMakeFiles/objects.dir/src/radix_tree.cpp.o
[ 22%] Building CXX object CMakeFiles/objects.dir/src/v1_decoder.cpp.o
[ 22%] Building CXX object CMakeFiles/objects.dir/src/v1_encoder.cpp.o
[ 23%] Building CXX object CMakeFiles/objects.dir/src/v2_decoder.cpp.o
[ 23%] Building CXX object CMakeFiles/objects.dir/src/v2_encoder.cpp.o
[ 23%] Building CXX object CMakeFiles/objects.dir/src/v3_1_encoder.cpp.o
[ 23%] Building CXX object CMakeFiles/objects.dir/src/xpub.cpp.o
[ 24%] Building CXX object CMakeFiles/objects.dir/src/xsub.cpp.o
[ 24%] Building CXX object CMakeFiles/objects.dir/src/zmq.cpp.o
[ 24%] Building CXX object CMakeFiles/objects.dir/src/zmq_utils.cpp.o
[ 24%] Building CXX object CMakeFiles/objects.dir/src/decoder_allocators.cpp.o
[ 25%] Building CXX object CMakeFiles/objects.dir/src/socket_poller.cpp.o
[ 25%] Building CXX object CMakeFiles/objects.dir/src/timers.cpp.o
[ 25%] Building CXX object CMakeFiles/objects.dir/src/radio.cpp.o
[ 25%] Building CXX object CMakeFiles/objects.dir/src/dish.cpp.o
[ 26%] Building CXX object CMakeFiles/objects.dir/src/udp_engine.cpp.o
[ 26%] Building CXX object CMakeFiles/objects.dir/src/udp_address.cpp.o
[ 26%] Building CXX object CMakeFiles/objects.dir/src/scatter.cpp.o
[ 26%] Building CXX object CMakeFiles/objects.dir/src/gather.cpp.o
[ 26%] Building CXX object CMakeFiles/objects.dir/src/ip_resolver.cpp.o
[ 27%] Building CXX object CMakeFiles/objects.dir/src/zap_client.cpp.o
[ 27%] Building CXX object CMakeFiles/objects.dir/src/zmtp_engine.cpp.o
[ 27%] Building CXX object CMakeFiles/objects.dir/src/stream_connecter_base.cpp.o
[ 27%] Building CXX object CMakeFiles/objects.dir/src/stream_listener_base.cpp.o
[ 28%] Building CXX object CMakeFiles/objects.dir/src/tipc_address.cpp.o
[ 28%] Building CXX object CMakeFiles/objects.dir/src/tipc_connecter.cpp.o
[ 28%] Building CXX object CMakeFiles/objects.dir/src/tipc_listener.cpp.o
[ 28%] Built target objects
[ 29%] Linking CXX shared library lib/libzmq.so
[ 29%] Linking CXX static library lib/libzmq.a
[ 29%] Built target libzmq-static
[ 30%] Building CXX object tests/CMakeFiles/testutil-static.dir/testutil.cpp.o
[ 30%] Building CXX object CMakeFiles/benchmark_radix_tree.dir/perf/benchmark_radix_tree.cpp.o
[ 30%] Building CXX object tests/CMakeFiles/testutil-static.dir/testutil_monitoring.cpp.o
[ 30%] Built target libzmq
[ 30%] Building CXX object tests/CMakeFiles/testutil-static.dir/testutil_security.cpp.o
[ 30%] Building CXX object tests/CMakeFiles/testutil-static.dir/testutil_unity.cpp.o
[ 30%] Building CXX object CMakeFiles/local_lat.dir/perf/local_lat.cpp.o
[ 30%] Building CXX object CMakeFiles/remote_lat.dir/perf/remote_lat.cpp.o
[ 30%] Linking CXX executable bin/local_lat
[ 30%] Linking CXX executable bin/remote_lat
[ 30%] Built target local_lat
[ 31%] Building CXX object CMakeFiles/local_thr.dir/perf/local_thr.cpp.o
[ 31%] Built target remote_lat
[ 32%] Linking CXX static library ../lib/libtestutil-static.a
[ 32%] Building CXX object CMakeFiles/remote_thr.dir/perf/remote_thr.cpp.o
[ 32%] Built target testutil-static
[ 33%] Building CXX object CMakeFiles/inproc_lat.dir/perf/inproc_lat.cpp.o
[ 33%] Linking CXX executable bin/local_thr
[ 34%] Linking CXX executable bin/remote_thr
[ 34%] Linking CXX executable bin/benchmark_radix_tree
[ 34%] Built target local_thr
[ 34%] Linking CXX executable bin/inproc_lat
[ 34%] Building CXX object CMakeFiles/inproc_thr.dir/perf/inproc_thr.cpp.o
[ 34%] Built target benchmark_radix_tree
[ 34%] Built target remote_thr
[ 34%] Building CXX object CMakeFiles/proxy_thr.dir/perf/proxy_thr.cpp.o
[ 34%] Building CXX object tests/CMakeFiles/testutil.dir/testutil.cpp.o
[ 34%] Built target inproc_lat
[ 34%] Building CXX object unittests/CMakeFiles/unittest_ypipe.dir/unittest_ypipe.cpp.o
[ 34%] Linking CXX executable bin/inproc_thr
[ 34%] Built target inproc_thr
[ 34%] Building CXX object unittests/CMakeFiles/unittest_poller.dir/unittest_poller.cpp.o
[ 35%] Linking CXX executable bin/proxy_thr
[ 36%] Building CXX object tests/CMakeFiles/testutil.dir/testutil_monitoring.cpp.o
[ 36%] Built target proxy_thr
[ 36%] Building CXX object unittests/CMakeFiles/unittest_mtrie.dir/unittest_mtrie.cpp.o
[ 36%] Linking CXX executable ../bin/unittest_ypipe
[ 36%] Building CXX object tests/CMakeFiles/testutil.dir/testutil_security.cpp.o
[ 36%] Built target unittest_ypipe
[ 36%] Building CXX object unittests/CMakeFiles/unittest_ip_resolver.dir/unittest_ip_resolver.cpp.o
[ 37%] Linking CXX executable ../bin/unittest_poller
[ 37%] Building CXX object tests/CMakeFiles/testutil.dir/testutil_unity.cpp.o
[ 37%] Built target unittest_poller
[ 37%] Building CXX object unittests/CMakeFiles/unittest_udp_address.dir/unittest_udp_address.cpp.o
[ 37%] Linking CXX static library ../lib/libtestutil.a
[ 37%] Built target testutil
[ 37%] Building CXX object unittests/CMakeFiles/unittest_radix_tree.dir/unittest_radix_tree.cpp.o
[ 38%] Linking CXX executable ../bin/unittest_udp_address
[ 38%] Linking CXX executable ../bin/unittest_mtrie
[ 39%] Linking CXX executable ../bin/unittest_ip_resolver
[ 39%] Built target unittest_udp_address
[ 39%] Building CXX object unittests/CMakeFiles/unittest_curve_encoding.dir/unittest_curve_encoding.cpp.o
[ 39%] Built target unittest_mtrie
[ 39%] Building CXX object tests/CMakeFiles/test_ancillaries.dir/test_ancillaries.cpp.o
[ 39%] Built target unittest_ip_resolver
[ 40%] Building CXX object tests/CMakeFiles/test_system.dir/test_system.cpp.o
[ 40%] Linking CXX executable ../bin/test_ancillaries
[ 40%] Linking CXX executable ../bin/test_system
[ 40%] Built target test_ancillaries
[ 41%] Building CXX object tests/CMakeFiles/test_pair_inproc.dir/test_pair_inproc.cpp.o
[ 41%] Built target test_system
[ 42%] Building CXX object tests/CMakeFiles/test_pair_tcp.dir/test_pair_tcp.cpp.o
[ 42%] Linking CXX executable ../bin/test_pair_inproc
[ 42%] Linking CXX executable ../bin/unittest_curve_encoding
[ 42%] Linking CXX executable ../bin/test_pair_tcp
[ 42%] Built target test_pair_inproc
[ 42%] Building CXX object tests/CMakeFiles/test_reqrep_inproc.dir/test_reqrep_inproc.cpp.o
[ 42%] Linking CXX executable ../bin/unittest_radix_tree
[ 42%] Built target test_pair_tcp
[ 42%] Building CXX object tests/CMakeFiles/test_reqrep_tcp.dir/test_reqrep_tcp.cpp.o
[ 42%] Built target unittest_curve_encoding
[ 43%] Building CXX object tests/CMakeFiles/test_hwm.dir/test_hwm.cpp.o
[ 44%] Linking CXX executable ../bin/test_reqrep_inproc
[ 44%] Built target unittest_radix_tree
[ 44%] Building CXX object tests/CMakeFiles/test_hwm_pubsub.dir/test_hwm_pubsub.cpp.o
[ 44%] Built target test_reqrep_inproc
[ 44%] Building CXX object tests/CMakeFiles/test_reqrep_device.dir/test_reqrep_device.cpp.o
[ 45%] Linking CXX executable ../bin/test_reqrep_tcp
[ 45%] Linking CXX executable ../bin/test_hwm
[ 45%] Built target test_reqrep_tcp
[ 46%] Building CXX object tests/CMakeFiles/test_sub_forward.dir/test_sub_forward.cpp.o
[ 46%] Built target test_hwm
[ 47%] Building CXX object tests/CMakeFiles/test_invalid_rep.dir/test_invalid_rep.cpp.o
[ 48%] Linking CXX executable ../bin/test_reqrep_device
[ 48%] Linking CXX executable ../bin/test_hwm_pubsub
[ 48%] Built target test_reqrep_device
[ 48%] Linking CXX executable ../bin/test_sub_forward
[ 49%] Building CXX object tests/CMakeFiles/test_msg_flags.dir/test_msg_flags.cpp.o
[ 49%] Linking CXX executable ../bin/test_invalid_rep
[ 49%] Built target test_hwm_pubsub
[ 49%] Building CXX object tests/CMakeFiles/test_msg_ffn.dir/test_msg_ffn.cpp.o
[ 49%] Built target test_sub_forward
[ 49%] Building CXX object tests/CMakeFiles/test_connect_resolve.dir/test_connect_resolve.cpp.o
[ 49%] Built target test_invalid_rep
[ 50%] Building CXX object tests/CMakeFiles/test_immediate.dir/test_immediate.cpp.o
[ 50%] Linking CXX executable ../bin/test_msg_flags
[ 50%] Linking CXX executable ../bin/test_msg_ffn
[ 50%] Linking CXX executable ../bin/test_connect_resolve
[ 50%] Built target test_msg_flags
[ 51%] Building CXX object tests/CMakeFiles/test_last_endpoint.dir/test_last_endpoint.cpp.o
[ 51%] Linking CXX executable ../bin/test_immediate
[ 51%] Built target test_msg_ffn
[ 52%] Building CXX object tests/CMakeFiles/test_term_endpoint.dir/test_term_endpoint.cpp.o
[ 52%] Built target test_connect_resolve
[ 52%] Building CXX object tests/CMakeFiles/test_router_mandatory.dir/test_router_mandatory.cpp.o
[ 52%] Built target test_immediate
[ 52%] Building CXX object tests/CMakeFiles/test_probe_router.dir/test_probe_router.cpp.o
[ 52%] Linking CXX executable ../bin/test_last_endpoint
[ 52%] Linking CXX executable ../bin/test_term_endpoint
[ 52%] Built target test_last_endpoint
[ 52%] Building CXX object tests/CMakeFiles/test_stream.dir/test_stream.cpp.o
[ 53%] Linking CXX executable ../bin/test_probe_router
[ 53%] Linking CXX executable ../bin/test_router_mandatory
[ 53%] Built target test_term_endpoint
[ 53%] Building CXX object tests/CMakeFiles/test_stream_empty.dir/test_stream_empty.cpp.o
[ 53%] Built target test_probe_router
[ 53%] Built target test_router_mandatory
[ 54%] Building CXX object tests/CMakeFiles/test_stream_disconnect.dir/test_stream_disconnect.cpp.o
[ 55%] Building CXX object tests/CMakeFiles/test_disconnect_inproc.dir/test_disconnect_inproc.cpp.o
[ 55%] Linking CXX executable ../bin/test_stream_empty
[ 55%] Linking CXX executable ../bin/test_stream
[ 55%] Built target test_stream_empty
[ 55%] Building CXX object tests/CMakeFiles/test_unbind_wildcard.dir/test_unbind_wildcard.cpp.o
[ 55%] Linking CXX executable ../bin/test_disconnect_inproc
[ 55%] Built target test_stream
[ 55%] Building CXX object tests/CMakeFiles/test_ctx_options.dir/test_ctx_options.cpp.o
[ 55%] Linking CXX executable ../bin/test_stream_disconnect
[ 55%] Built target test_disconnect_inproc
[ 55%] Building CXX object tests/CMakeFiles/test_ctx_destroy.dir/test_ctx_destroy.cpp.o
[ 55%] Built target test_stream_disconnect
[ 56%] Building CXX object tests/CMakeFiles/test_security_no_zap_handler.dir/test_security_no_zap_handler.cpp.o
[ 56%] Linking CXX executable ../bin/test_unbind_wildcard
[ 56%] Linking CXX executable ../bin/test_ctx_options
[ 56%] Built target test_unbind_wildcard
[ 56%] Building CXX object tests/CMakeFiles/test_security_null.dir/test_security_null.cpp.o
[ 56%] Linking CXX executable ../bin/test_ctx_destroy
[ 56%] Linking CXX executable ../bin/test_security_no_zap_handler
[ 56%] Built target test_ctx_options
[ 57%] Building CXX object tests/CMakeFiles/test_security_plain.dir/test_security_plain.cpp.o
[ 57%] Built target test_ctx_destroy
[ 57%] Built target test_security_no_zap_handler
[ 57%] Building CXX object tests/CMakeFiles/test_security_zap.dir/test_security_zap.cpp.o
[ 57%] Building CXX object tests/CMakeFiles/test_iov.dir/test_iov.cpp.o
[ 57%] Linking CXX executable ../bin/test_security_null
[ 57%] Linking CXX executable ../bin/test_security_plain
[ 57%] Built target test_security_null
[ 58%] Building CXX object tests/CMakeFiles/test_spec_req.dir/test_spec_req.cpp.o
[ 58%] Linking CXX executable ../bin/test_iov
[ 58%] Built target test_security_plain
[ 58%] Building CXX object tests/CMakeFiles/test_spec_rep.dir/test_spec_rep.cpp.o
[ 58%] Built target test_iov
[ 58%] Linking CXX executable ../bin/test_security_zap
[ 58%] Building CXX object tests/CMakeFiles/test_spec_dealer.dir/test_spec_dealer.cpp.o
[ 58%] Linking CXX executable ../bin/test_spec_req
[ 58%] Built target test_security_zap
[ 58%] Building CXX object tests/CMakeFiles/test_spec_router.dir/test_spec_router.cpp.o
[ 58%] Linking CXX executable ../bin/test_spec_rep
[ 58%] Built target test_spec_req
[ 59%] Building CXX object tests/CMakeFiles/test_spec_pushpull.dir/test_spec_pushpull.cpp.o
[ 59%] Linking CXX executable ../bin/test_spec_dealer
[ 59%] Built target test_spec_rep
[ 59%] Building CXX object tests/CMakeFiles/test_req_correlate.dir/test_req_correlate.cpp.o
[ 59%] Linking CXX executable ../bin/test_spec_router
[ 59%] Built target test_spec_dealer
[ 59%] Building CXX object tests/CMakeFiles/test_req_relaxed.dir/test_req_relaxed.cpp.o
[ 60%] Linking CXX executable ../bin/test_req_correlate
[ 60%] Built target test_spec_router
[ 60%] Building CXX object tests/CMakeFiles/test_conflate.dir/test_conflate.cpp.o
[ 60%] Linking CXX executable ../bin/test_spec_pushpull
[ 60%] Built target test_req_correlate
[ 60%] Building CXX object tests/CMakeFiles/test_inproc_connect.dir/test_inproc_connect.cpp.o
[ 60%] Linking CXX executable ../bin/test_req_relaxed
[ 60%] Linking CXX executable ../bin/test_conflate
[ 60%] Built target test_spec_pushpull
[ 60%] Building CXX object tests/CMakeFiles/test_issue_566.dir/test_issue_566.cpp.o
[ 60%] Built target test_req_relaxed
[ 60%] Building CXX object tests/CMakeFiles/test_shutdown_stress.dir/test_shutdown_stress.cpp.o
[ 60%] Built target test_conflate
[ 60%] Building CXX object tests/CMakeFiles/test_timeo.dir/test_timeo.cpp.o
[ 60%] Linking CXX executable ../bin/test_inproc_connect
[ 60%] Linking CXX executable ../bin/test_issue_566
[ 60%] Linking CXX executable ../bin/test_shutdown_stress
[ 60%] Linking CXX executable ../bin/test_timeo
[ 60%] Built target test_inproc_connect
[ 60%] Built target test_issue_566
[ 60%] Building CXX object tests/CMakeFiles/test_many_sockets.dir/test_many_sockets.cpp.o
[ 60%] Building CXX object tests/CMakeFiles/test_diffserv.dir/test_diffserv.cpp.o
[ 60%] Built target test_shutdown_stress
[ 60%] Building CXX object tests/CMakeFiles/test_connect_rid.dir/test_connect_rid.cpp.o
[ 60%] Built target test_timeo
[ 60%] Building CXX object tests/CMakeFiles/test_xpub_nodrop.dir/test_xpub_nodrop.cpp.o
[ 60%] Linking CXX executable ../bin/test_diffserv
[ 61%] Linking CXX executable ../bin/test_xpub_nodrop
[ 62%] Linking CXX executable ../bin/test_connect_rid
[ 62%] Built target test_diffserv
[ 62%] Building CXX object tests/CMakeFiles/test_pub_invert_matching.dir/test_pub_invert_matching.cpp.o
[ 62%] Linking CXX executable ../bin/test_many_sockets
[ 62%] Built target test_xpub_nodrop
[ 62%] Built target test_connect_rid
[ 63%] Building CXX object tests/CMakeFiles/test_setsockopt.dir/test_setsockopt.cpp.o
[ 64%] Building CXX object tests/CMakeFiles/test_sockopt_hwm.dir/test_sockopt_hwm.cpp.o
[ 64%] Built target test_many_sockets
[ 64%] Building CXX object tests/CMakeFiles/test_heartbeats.dir/test_heartbeats.cpp.o
[ 65%] Linking CXX executable ../bin/test_pub_invert_matching
[ 65%] Built target test_pub_invert_matching
[ 65%] Linking CXX executable ../bin/test_setsockopt
[ 65%] Building CXX object tests/CMakeFiles/test_atomics.dir/test_atomics.cpp.o
[ 65%] Linking CXX executable ../bin/test_sockopt_hwm
[ 65%] Built target test_setsockopt
[ 65%] Built target test_sockopt_hwm
[ 65%] Building CXX object tests/CMakeFiles/test_bind_src_address.dir/test_bind_src_address.cpp.o
[ 65%] Building CXX object tests/CMakeFiles/test_capabilities.dir/test_capabilities.cpp.o
[ 65%] Linking CXX executable ../bin/test_atomics
[ 65%] Linking CXX executable ../bin/test_heartbeats
[ 66%] Linking CXX executable ../bin/test_bind_src_address
[ 66%] Built target test_heartbeats
[ 66%] Built target test_atomics
[ 66%] Building CXX object tests/CMakeFiles/test_router_handover.dir/test_router_handover.cpp.o
[ 68%] Linking CXX executable ../bin/test_capabilities
[ 68%] Building CXX object tests/CMakeFiles/test_metadata.dir/test_metadata.cpp.o
[ 68%] Built target test_bind_src_address
[ 69%] Building CXX object tests/CMakeFiles/test_srcfd.dir/test_srcfd.cpp.o
[ 69%] Built target test_capabilities
[ 69%] Building CXX object tests/CMakeFiles/test_stream_timeout.dir/test_stream_timeout.cpp.o
[ 70%] Linking CXX executable ../bin/test_router_handover
[ 70%] Linking CXX executable ../bin/test_metadata
[ 70%] Linking CXX executable ../bin/test_srcfd
[ 70%] Built target test_router_handover
[ 70%] Building CXX object tests/CMakeFiles/test_xpub_manual.dir/test_xpub_manual.cpp.o
[ 70%] Built target test_metadata
[ 70%] Linking CXX executable ../bin/test_stream_timeout
[ 70%] Building CXX object tests/CMakeFiles/test_xpub_topic.dir/test_xpub_topic.cpp.o
[ 70%] Built target test_srcfd
[ 70%] Building CXX object tests/CMakeFiles/test_xpub_welcome_msg.dir/test_xpub_welcome_msg.cpp.o
[ 70%] Built target test_stream_timeout
[ 70%] Building CXX object tests/CMakeFiles/test_xpub_verbose.dir/test_xpub_verbose.cpp.o
[ 70%] Linking CXX executable ../bin/test_xpub_topic
[ 70%] Linking CXX executable ../bin/test_xpub_welcome_msg
[ 70%] Built target test_xpub_topic
[ 70%] Building CXX object tests/CMakeFiles/test_base85.dir/test_base85.cpp.o
[ 70%] Built target test_xpub_welcome_msg
[ 71%] Linking CXX executable ../bin/test_xpub_manual
[ 71%] Building CXX object tests/CMakeFiles/test_bind_after_connect_tcp.dir/test_bind_after_connect_tcp.cpp.o
[ 72%] Linking CXX executable ../bin/test_xpub_verbose
[ 72%] Built target test_xpub_manual
[ 73%] Building CXX object tests/CMakeFiles/test_sodium.dir/test_sodium.cpp.o
[ 73%] Built target test_xpub_verbose
[ 74%] Building CXX object tests/CMakeFiles/test_monitor.dir/test_monitor.cpp.o
[ 74%] Linking CXX executable ../bin/test_bind_after_connect_tcp
[ 75%] Linking CXX executable ../bin/test_base85
[ 75%] Built target test_bind_after_connect_tcp
[ 75%] Linking CXX executable ../bin/test_sodium
[ 75%] Building CXX object tests/CMakeFiles/test_socket_null.dir/test_socket_null.cpp.o
[ 75%] Built target test_base85
[ 75%] Building CXX object tests/CMakeFiles/test_reconnect_ivl.dir/test_reconnect_ivl.cpp.o
[ 75%] Built target test_sodium
[ 75%] Building CXX object tests/CMakeFiles/test_reconnect_options.dir/test_reconnect_options.cpp.o
[ 75%] Linking CXX executable ../bin/test_monitor
[ 75%] Linking CXX executable ../bin/test_socket_null
[ 76%] Linking CXX executable ../bin/test_reconnect_ivl
[ 76%] Built target test_monitor
[ 76%] Building CXX object tests/CMakeFiles/test_tcp_accept_filter.dir/test_tcp_accept_filter.cpp.o
[ 76%] Built target test_socket_null
[ 76%] Built target test_reconnect_ivl
[ 76%] Building CXX object tests/CMakeFiles/test_mock_pub_sub.dir/test_mock_pub_sub.cpp.o
[ 76%] Building CXX object tests/CMakeFiles/test_security_gssapi.dir/test_security_gssapi.cpp.o
[ 76%] Linking CXX executable ../bin/test_reconnect_options
[ 76%] Built target test_reconnect_options
[ 76%] Building CXX object tests/CMakeFiles/test_socks.dir/test_socks.cpp.o
[ 76%] Linking CXX executable ../bin/test_tcp_accept_filter
[ 76%] Linking CXX executable ../bin/test_mock_pub_sub
[ 76%] Linking CXX executable ../bin/test_security_gssapi
[ 76%] Built target test_tcp_accept_filter
[ 76%] Building CXX object tests/CMakeFiles/test_connect_null_fuzzer.dir/test_connect_null_fuzzer.cpp.o
[ 76%] Built target test_mock_pub_sub
[ 76%] Building CXX object tests/CMakeFiles/test_bind_null_fuzzer.dir/test_bind_null_fuzzer.cpp.o
[ 76%] Built target test_security_gssapi
[ 76%] Building CXX object tests/CMakeFiles/test_connect_fuzzer.dir/test_connect_fuzzer.cpp.o
[ 77%] Linking CXX executable ../bin/test_connect_null_fuzzer
[ 77%] Linking CXX executable ../bin/test_bind_null_fuzzer
[ 77%] Built target test_connect_null_fuzzer
[ 77%] Building CXX object tests/CMakeFiles/test_bind_fuzzer.dir/test_bind_fuzzer.cpp.o
[ 77%] Built target test_bind_null_fuzzer
[ 78%] Building CXX object tests/CMakeFiles/test_ipc_wildcard.dir/test_ipc_wildcard.cpp.o
[ 78%] Linking CXX executable ../bin/test_connect_fuzzer
[ 78%] Linking CXX executable ../bin/test_ipc_wildcard
[ 78%] Built target test_connect_fuzzer
[ 78%] Building CXX object tests/CMakeFiles/test_pair_ipc.dir/test_pair_ipc.cpp.o
[ 78%] Linking CXX executable ../bin/test_socks
[ 78%] Built target test_ipc_wildcard
[ 78%] Building CXX object tests/CMakeFiles/test_reqrep_ipc.dir/test_reqrep_ipc.cpp.o
[ 79%] Linking CXX executable ../bin/test_bind_fuzzer
[ 79%] Built target test_socks
[ 79%] Building CXX object tests/CMakeFiles/test_rebind_ipc.dir/test_rebind_ipc.cpp.o
[ 79%] Linking CXX executable ../bin/test_reqrep_ipc
[ 79%] Built target test_bind_fuzzer
[ 79%] Building CXX object tests/CMakeFiles/test_proxy.dir/test_proxy.cpp.o
[ 79%] Linking CXX executable ../bin/test_rebind_ipc
[ 79%] Built target test_reqrep_ipc
[ 79%] Building CXX object tests/CMakeFiles/test_proxy_hwm.dir/test_proxy_hwm.cpp.o
[ 79%] Linking CXX executable ../bin/test_pair_ipc
[ 79%] Built target test_rebind_ipc
[ 79%] Building CXX object tests/CMakeFiles/test_proxy_single_socket.dir/test_proxy_single_socket.cpp.o
[ 79%] Built target test_pair_ipc
[ 79%] Building CXX object tests/CMakeFiles/test_proxy_steerable.dir/test_proxy_steerable.cpp.o
[ 79%] Linking CXX executable ../bin/test_proxy
[ 80%] Linking CXX executable ../bin/test_proxy_hwm
[ 80%] Linking CXX executable ../bin/test_proxy_single_socket
[ 80%] Built target test_proxy
[ 80%] Building CXX object tests/CMakeFiles/test_proxy_terminate.dir/test_proxy_terminate.cpp.o
[ 80%] Built target test_proxy_hwm
[ 81%] Building CXX object tests/CMakeFiles/test_getsockopt_memset.dir/test_getsockopt_memset.cpp.o
[ 81%] Built target test_proxy_single_socket
[ 82%] Building CXX object tests/CMakeFiles/test_filter_ipc.dir/test_filter_ipc.cpp.o
[ 83%] Linking CXX executable ../bin/test_proxy_steerable
[ 83%] Linking CXX executable ../bin/test_proxy_terminate
[ 83%] Linking CXX executable ../bin/test_getsockopt_memset
[ 83%] Built target test_proxy_steerable
[ 84%] Building CXX object tests/CMakeFiles/test_stream_exceeds_buffer.dir/test_stream_exceeds_buffer.cpp.o
[ 84%] Linking CXX executable ../bin/test_filter_ipc
[ 84%] Built target test_proxy_terminate
[ 84%] Building CXX object tests/CMakeFiles/test_router_mandatory_hwm.dir/test_router_mandatory_hwm.cpp.o
[ 84%] Built target test_getsockopt_memset
[ 84%] Building CXX object tests/CMakeFiles/test_use_fd.dir/test_use_fd.cpp.o
[ 84%] Built target test_filter_ipc
[ 84%] Building CXX object tests/CMakeFiles/test_zmq_poll_fd.dir/test_zmq_poll_fd.cpp.o
[ 84%] Linking CXX executable ../bin/test_stream_exceeds_buffer
[ 85%] Linking CXX executable ../bin/test_router_mandatory_hwm
[ 86%] Linking CXX executable ../bin/test_use_fd
[ 86%] Built target test_stream_exceeds_buffer
[ 86%] Building CXX object tests/CMakeFiles/test_fork.dir/test_fork.cpp.o
[ 86%] Linking CXX executable ../bin/test_zmq_poll_fd
[ 86%] Built target test_router_mandatory_hwm
[ 86%] Building CXX object tests/CMakeFiles/test_abstract_ipc.dir/test_abstract_ipc.cpp.o
[ 86%] Built target test_use_fd
[ 86%] Building CXX object tests/CMakeFiles/test_address_tipc.dir/test_address_tipc.cpp.o
[ 86%] Built target test_zmq_poll_fd
[ 86%] Building CXX object tests/CMakeFiles/test_pair_tipc.dir/test_pair_tipc.cpp.o
[ 86%] Linking CXX executable ../bin/test_fork
[ 86%] Linking CXX executable ../bin/test_abstract_ipc
[ 87%] Linking CXX executable ../bin/test_address_tipc
[ 87%] Built target test_fork
[ 87%] Linking CXX executable ../bin/test_pair_tipc
[ 87%] Building CXX object tests/CMakeFiles/test_reqrep_device_tipc.dir/test_reqrep_device_tipc.cpp.o
[ 87%] Built target test_abstract_ipc
[ 87%] Building CXX object tests/CMakeFiles/test_reqrep_tipc.dir/test_reqrep_tipc.cpp.o
[ 87%] Built target test_address_tipc
[ 87%] Built target test_pair_tipc
[ 87%] Building CXX object tests/CMakeFiles/test_router_mandatory_tipc.dir/test_router_mandatory_tipc.cpp.o
[ 87%] Building CXX object tests/CMakeFiles/test_sub_forward_tipc.dir/test_sub_forward_tipc.cpp.o
[ 87%] Linking CXX executable ../bin/test_reqrep_tipc
[ 87%] Linking CXX executable ../bin/test_reqrep_device_tipc
[ 87%] Linking CXX executable ../bin/test_router_mandatory_tipc
[ 87%] Linking CXX executable ../bin/test_sub_forward_tipc
[ 87%] Built target test_reqrep_tipc
[ 87%] Building CXX object tests/CMakeFiles/test_connect_delay_tipc.dir/test_connect_delay_tipc.cpp.o
[ 87%] Built target test_reqrep_device_tipc
[ 88%] Building CXX object tests/CMakeFiles/test_shutdown_stress_tipc.dir/test_shutdown_stress_tipc.cpp.o
[ 88%] Built target test_router_mandatory_tipc
[ 88%] Building CXX object tests/CMakeFiles/test_term_endpoint_tipc.dir/test_term_endpoint_tipc.cpp.o
[ 88%] Built target test_sub_forward_tipc
[ 88%] Building CXX object tests/CMakeFiles/test_poller.dir/test_poller.cpp.o
[ 88%] Linking CXX executable ../bin/test_shutdown_stress_tipc
[ 89%] Linking CXX executable ../bin/test_connect_delay_tipc
[ 89%] Linking CXX executable ../bin/test_term_endpoint_tipc
[ 89%] Built target test_shutdown_stress_tipc
[ 89%] Building CXX object tests/CMakeFiles/test_thread_safe.dir/test_thread_safe.cpp.o
[ 89%] Built target test_connect_delay_tipc
[ 89%] Building CXX object tests/CMakeFiles/test_client_server.dir/test_client_server.cpp.o
[ 89%] Built target test_term_endpoint_tipc
[ 89%] Building CXX object tests/CMakeFiles/test_timers.dir/test_timers.cpp.o
[ 90%] Linking CXX executable ../bin/test_thread_safe
[ 91%] Linking CXX executable ../bin/test_client_server
[ 92%] Linking CXX executable ../bin/test_timers
[ 92%] Built target test_thread_safe
[ 92%] Building CXX object tests/CMakeFiles/test_radio_dish.dir/test_radio_dish.cpp.o
[ 92%] Built target test_client_server
[ 92%] Building CXX object tests/CMakeFiles/test_scatter_gather.dir/test_scatter_gather.cpp.o
[ 92%] Linking CXX executable ../bin/test_poller
[ 92%] Built target test_timers
[ 93%] Building CXX object tests/CMakeFiles/test_dgram.dir/test_dgram.cpp.o
[ 93%] Linking CXX executable ../bin/test_scatter_gather
[ 93%] Built target test_poller
[ 93%] Building CXX object tests/CMakeFiles/test_app_meta.dir/test_app_meta.cpp.o
[ 93%] Linking CXX executable ../bin/test_dgram
[ 93%] Built target test_scatter_gather
[ 94%] Linking CXX executable ../bin/test_radio_dish
[ 94%] Building CXX object tests/CMakeFiles/test_router_notify.dir/test_router_notify.cpp.o
[ 94%] Built target test_dgram
[ 94%] Building CXX object tests/CMakeFiles/test_xpub_manual_last_value.dir/test_xpub_manual_last_value.cpp.o
[ 95%] Linking CXX executable ../bin/test_app_meta
[ 95%] Built target test_radio_dish
[ 95%] Building CXX object tests/CMakeFiles/test_peer.dir/test_peer.cpp.o
[ 95%] Built target test_app_meta
[ 95%] Building CXX object tests/CMakeFiles/test_msg_init.dir/test_msg_init.cpp.o
[ 96%] Linking CXX executable ../bin/test_router_notify
[ 97%] Linking CXX executable ../bin/test_peer
[ 97%] Built target test_router_notify
[ 97%] Building CXX object tests/CMakeFiles/test_channel.dir/test_channel.cpp.o
[ 97%] Built target test_peer
[ 97%] Linking CXX executable ../bin/test_msg_init
[ 98%] Building CXX object tests/CMakeFiles/test_hello_msg.dir/test_hello_msg.cpp.o
[ 98%] Linking CXX executable ../bin/test_xpub_manual_last_value
[ 98%] Linking CXX executable ../bin/test_channel
[ 98%] Built target test_msg_init
[ 98%] Building CXX object tests/CMakeFiles/test_disconnect_msg.dir/test_disconnect_msg.cpp.o
[ 98%] Built target test_xpub_manual_last_value
[ 98%] Building CXX object tests/CMakeFiles/test_hiccup_msg.dir/test_hiccup_msg.cpp.o
[ 98%] Linking CXX executable ../bin/test_hello_msg
[ 98%] Built target test_channel
[ 98%] Building CXX object tests/CMakeFiles/test_zmq_ppoll_fd.dir/test_zmq_ppoll_fd.cpp.o
[ 98%] Built target test_hello_msg
[ 98%] Linking CXX executable ../bin/test_disconnect_msg
[ 98%] Building CXX object tests/CMakeFiles/test_xsub_verbose.dir/test_xsub_verbose.cpp.o
[ 98%] Linking CXX executable ../bin/test_hiccup_msg
[ 99%] Linking CXX executable ../bin/test_zmq_ppoll_fd
[ 99%] Built target test_disconnect_msg
[ 99%] Building CXX object tests/CMakeFiles/test_pubsub_topics_count.dir/test_pubsub_topics_count.cpp.o
[ 99%] Built target test_hiccup_msg
[ 99%] Building CXX object tests/CMakeFiles/test_zmq_ppoll_signals.dir/test_zmq_ppoll_signals.cpp.o
[100%] Linking CXX executable ../bin/test_xsub_verbose
[100%] Built target test_zmq_ppoll_fd
[100%] Building CXX object tests/CMakeFiles/test_busy_poll.dir/test_busy_poll.cpp.o
[100%] Built target test_xsub_verbose
[100%] Building CXX object tests/CMakeFiles/test_ws_transport.dir/test_ws_transport.cpp.o
[100%] Linking CXX executable ../bin/test_pubsub_topics_count
[100%] Linking CXX executable ../bin/test_zmq_ppoll_signals
[100%] Linking CXX executable ../bin/test_busy_poll
[100%] Built target test_pubsub_topics_count
[100%] Built target test_zmq_ppoll_signals
[100%] Built target test_busy_poll
[100%] Linking CXX executable ../bin/test_ws_transport
[100%] Built target test_ws_transport
Install the project...
-- Install configuration: "Release"
-- Installing: /usr/local/lib/pkgconfig/libzmq.pc
-- Installing: /usr/local/bin/local_lat
-- Set non-toolchain portion of runtime path of "/usr/local/bin/local_lat" to ""
-- Installing: /usr/local/bin/remote_lat
-- Set non-toolchain portion of runtime path of "/usr/local/bin/remote_lat" to ""
-- Installing: /usr/local/bin/local_thr
-- Set non-toolchain portion of runtime path of "/usr/local/bin/local_thr" to ""
-- Installing: /usr/local/bin/remote_thr
-- Set non-toolchain portion of runtime path of "/usr/local/bin/remote_thr" to ""
-- Installing: /usr/local/bin/inproc_lat
-- Set non-toolchain portion of runtime path of "/usr/local/bin/inproc_lat" to ""
-- Installing: /usr/local/bin/inproc_thr
-- Set non-toolchain portion of runtime path of "/usr/local/bin/inproc_thr" to ""
-- Installing: /usr/local/bin/proxy_thr
-- Set non-toolchain portion of runtime path of "/usr/local/bin/proxy_thr" to ""
-- Installing: /usr/local/lib/libzmq.so.5.2.6
-- Installing: /usr/local/lib/libzmq.so.5
-- Installing: /usr/local/lib/libzmq.so
-- Installing: /usr/local/include/zmq.h
-- Installing: /usr/local/include/zmq_utils.h
-- Installing: /usr/local/lib/libzmq.a
-- Up-to-date: /usr/local/include/zmq.h
-- Up-to-date: /usr/local/include/zmq_utils.h
-- Installing: /usr/local/share/zmq/AUTHORS.txt
-- Installing: /usr/local/share/zmq/LICENSE.txt
-- Installing: /usr/local/share/zmq/NEWS.txt
-- Installing: /usr/local/lib/cmake/ZeroMQ/ZeroMQTargets.cmake
-- Installing: /usr/local/lib/cmake/ZeroMQ/ZeroMQTargets-release.cmake
-- Installing: /usr/local/lib/cmake/ZeroMQ/ZeroMQConfig.cmake
-- Installing: /usr/local/lib/cmake/ZeroMQ/ZeroMQConfigVersion.cmake

2.3安装cppzmq库

  1. Build cppzmq via cmake. This does an out of source build and installs the build files
    • git clone https://github.com/zeromq/cppzmq.git
    • cd cppzmq
    • mkdir build
    • cd build
    • cmake .. or cmake -DCPPZMQ_BUILD_TESTS=OFF .. to skip building tests
    • sudo make -j4 install
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq/build$ cd ..
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/libzmq$ cd ..
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project$ cd cppzmq/
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/cppzmq$ mkdir build
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/cppzmq$ cd build/
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/cppzmq/build$ cmake ..
-- Detected CPPZMQ Version - 4.11.0
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- cppzmq v4.11.0
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
[ 11%] Creating directories for 'catch2-populate'
[ 22%] Performing download step (git clone) for 'catch2-populate'
Cloning into 'catch2-src'...
error: RPC failed; curl 16 Error in the HTTP2 framing layer
fatal: expected flush after ref listing
Cloning into 'catch2-src'...
fatal: unable to access 'https://github.com/catchorg/Catch2.git/': Failed to connect to github.com port 443 after 130307 ms: Connection timed out
Cloning into 'catch2-src'...
fatal: unable to access 'https://github.com/catchorg/Catch2.git/': Failed to connect to github.com port 443 after 131041 ms: Connection timed out
Had to git clone more than once: 3 times.
CMake Error at catch2-subbuild/catch2-populate-prefix/tmp/catch2-populate-gitclone.cmake:50 (message):
  Failed to clone repository: 'https://github.com/catchorg/Catch2.git'


gmake[2]: *** [CMakeFiles/catch2-populate.dir/build.make:102: catch2-populate-prefix/src/catch2-populate-stamp/catch2-populate-download] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:87: CMakeFiles/catch2-populate.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2

CMake Error at /usr/local/share/cmake-4.1/Modules/FetchContent.cmake:1918 (message):
  Build step for catch2 failed: 2
Call Stack (most recent call first):
  /usr/local/share/cmake-4.1/Modules/FetchContent.cmake:1609 (__FetchContent_populateSubbuild)
  /usr/local/share/cmake-4.1/Modules/FetchContent.cmake:2145:EVAL:2 (__FetchContent_doPopulation)
  /usr/local/share/cmake-4.1/Modules/FetchContent.cmake:2145 (cmake_language)
  /usr/local/share/cmake-4.1/Modules/FetchContent.cmake:2384 (__FetchContent_Populate)
  tests/CMakeLists.txt:13 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/cppzmq/build$ cmake -DCPPZMQ_BUILD_TESTS=OFF ..
-- Detected CPPZMQ Version - 4.11.0
-- cppzmq v4.11.0
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/Tronlong/mmcblk0p8/project_code/project/cppzmq/build
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/cppzmq/build$ sudo make -j4 install
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/include/zmq.hpp
-- Installing: /usr/local/include/zmq_addon.hpp
-- Installing: /usr/local/lib/pkgconfig/cppzmq.pc
-- Installing: /usr/local/share/cmake/cppzmq/cppzmqTargets.cmake
-- Installing: /usr/local/share/cmake/cppzmq/cppzmqConfig.cmake
-- Installing: /usr/local/share/cmake/cppzmq/cppzmqConfigVersion.cmake
-- Installing: /usr/local/share/cmake/cppzmq/libzmq-pkg-config/FindZeroMQ.cmake
  1. Alternatively, build cppzmq via vcpkg. This does an out of source build and installs the build files
    • git clone https://github.com/Microsoft/vcpkg.git
    • cd vcpkg
    • ./bootstrap-vcpkg.sh (bootstrap-vcpkg.bat for Powershell)
    • ./vcpkg integrate install
    • ./vcpkg install cppzmq

📡 3、发布-订阅模式(PUB/SUB)

🧩 模型介绍

发布者(Publisher) 持续发布主题消息;Win11的VS2022环境
订阅者(Subscriber) 根据主题过滤并接收对应内容。Ubuntu22.04的RK3576环境


🖥️ 示例 1:Publisher 发送多种主题消息

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "zmq.h"
#include <string>
#include <thread>
#include <atomic>
#include <iostream>
int main()
{
    void* context = zmq_ctx_new();
    assert(context != NULL);

    void* publisher = zmq_socket(context, ZMQ_PUB);
    assert(publisher != NULL);

    int ret = zmq_bind(publisher, "tcp://*:5555");
    assert(ret == 0);

    int i = 0;
    while (1)
    {
        char szBuf[1024] = { 0 };
        snprintf(szBuf, sizeof(szBuf), "server i=%d", i);
        ret = zmq_send(publisher, szBuf, strlen(szBuf) + 1, 0);
        i++;
        printf("[SENT szBuf] %s\n", szBuf);
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    zmq_close(publisher);
    zmq_ctx_destroy(context);

    return 0;
}

直接Debug运行
在这里插入图片描述

🖥️ 示例 2:Subscriber 订阅并打印消息

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "zmq.h"
 
int main()
{
    printf("Hello world!\n");
 
    void* context = zmq_ctx_new();
    assert(context != NULL);
 
    void* subscriber = zmq_socket(context, ZMQ_SUB);
    assert(subscriber != NULL);
 
    int ret = zmq_connect(subscriber, "tcp://192.168.170.53:5555");
    assert(ret == 0);
 
    ret = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
    assert(ret == 0);
 
    while(1)
    {
        printf("into while\n");
        char szBuf[1024] = {0};
        ret = zmq_recv(subscriber, szBuf, sizeof(szBuf) - 1, 0);
        if (ret > 0)
        {
            printf("%s\n", szBuf);
        }
    }
 
    zmq_close(subscriber);
    zmq_ctx_destroy(context);
 
    return 0;
}

请注意一下ip地址,我现在

主机 从机
系统 win11 Ubuntu22.04
名称 Publisher Subscriber
地址 192.168.170.53 192.168.170.77

在代码中需要注意一下关于192.168.170.53地址,你都需要自己替换到目标服务器地址哦🤣🤣🤣🤣

int ret = zmq_connect(subscriber, "tcp://192.168.170.53:5555");

Cmake文件配置

cmake_minimum_required(VERSION 3.10)
project(zmq_client)
# 查找 ZeroMQ 库
find_library(ZMQ_LIBRARY NAMES zmq)
find_path(ZMQ_INCLUDE_DIR zmq.h)


set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(EXE_NAME zmq_client)
file(GLOB SOURCES "src/*.cpp")
include_directories(include)
add_executable(${EXE_NAME} ${SOURCES})

# 链接 ZeroMQ 库
target_link_libraries(zmq_client ${ZMQ_LIBRARY})
target_include_directories(zmq_client PRIVATE ${ZMQ_INCLUDE_DIR})

运行另外个终端,编译运行指令

mkdir build&&cd build
cmake ..&&make
./zmp_client

Ctrl+C停止运行

启动下面的程序就可以收到数据啦
在这里插入图片描述

Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ make clean
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ cmake ..&make
[1] 203962
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/Tronlong/mmcblk0p8/project_code/project/zmp_client/build
[ 25%] Building CXX object CMakeFiles/zmq_client.dir/src/main.cpp.o
[ 50%] Building CXX object CMakeFiles/zmq_client.dir/src/main1.cpp.o
[ 75%] Building CXX object CMakeFiles/zmq_client.dir/src/main2.cpp.o
[100%] Linking CXX executable zmq_client
[100%] Built target zmq_client
[1]+  Done                    cmake ..
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ ./zmq_client 
Hello world!
into while
server i=28
into while
server i=29
into while
server i=30
into while
server i=31
into while
server i=32
into while
server i=33
into while
server i=34
into while
server i=35
into while
server i=36

🔁 四、双向发布订阅(两个节点互发)

在某些设备(如无人船)中,既需要发布传感器数据,也要接收控制命令。
可以让两个进程各自绑定 PUB/SUB 套接字,互为发布者与订阅者


🌐 进程 1:Host 节点(发布命令 / 订阅传感器)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "zmq.h"
#include <string>
#include <thread>
#include <atomic>
#include <iostream>
#include <chrono>

std::atomic<bool> g_running{ true };

// 接收数据线程函数
void recv_thread(void* subscriber) {
    while (g_running) {
        char szBuf[1024] = { 0 };
        int ret = zmq_recv(subscriber, szBuf, sizeof(szBuf) - 1, 0);
        if (ret > 0) {
            printf("Received data: %s\n", szBuf);
        }
        else {
            // 处理错误或超时,这里我们简单等待
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
}

int main() {
    void* context = zmq_ctx_new();
    assert(context != NULL);

    // 创建发布者socket(发送命令)
    void* publisher = zmq_socket(context, ZMQ_PUB);
    assert(publisher != NULL);
    int ret = zmq_bind(publisher, "tcp://*:5555");
    assert(ret == 0);

    // 创建订阅者socket(接收数据)
    void* subscriber = zmq_socket(context, ZMQ_SUB);
    assert(subscriber != NULL);
    ret = zmq_bind(subscriber, "tcp://*:5556");
    assert(ret == 0);
    ret = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
    assert(ret == 0);

    // 启动接收线程
    std::thread t(recv_thread, subscriber);

    // 主循环用于发送命令
    int i = 0;
    while (g_running) {
        char szBuf[1024] = { 0 };
        snprintf(szBuf, sizeof(szBuf), "Command %d", i);
        ret = zmq_send(publisher, szBuf, strlen(szBuf) + 1, 0);
        if (ret < 0) {
            printf("Send failed: %s\n", zmq_strerror(errno));
        }
        else {
            printf("Sent command: %s\n", szBuf);
        }
        i++;

        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    // 清理
    t.join();
    zmq_close(publisher);
    zmq_close(subscriber);
    zmq_ctx_destroy(context);

    return 0;
}

直接Debug走起,如果启动下面线程就可以收到数据
在这里插入图片描述
在这里插入图片描述

Received data: SENSOR_DATA_0 from client
Received data: HEARTBEAT_0
Sent command: Command 32
Sent command: Command 33
Received data: SENSOR_DATA_1 from client
Received data: HEARTBEAT_1
Sent command: Command 34
Sent command: Command 35
Received data: SENSOR_DATA_2 from client
Received data: HEARTBEAT_2
Sent command: Command 36
Sent command: Command 37
Received data: SENSOR_DATA_3 from client
Received data: HEARTBEAT_3
Sent command: Command 38
Sent command: Command 39
Received data: SENSOR_DATA_4 from client
Received data: HEARTBEAT_4
Sent command: Command 40

🌐 进程 2:Device 节点(发布传感器 / 订阅命令)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>  // 添加这个头文件
#include <signal.h>
#include "zmq.h"
#include <atomic>
#include <thread>
#include <iostream>  // 建议也添加这个
#include <chrono>    // 建议也添加这个

std::atomic<bool> g_running{ true };

void signal_handler(int sig) {
    printf("Received signal %d, shutting down...\n", sig);
    g_running = false;
}

// 接收线程函数 - 接收服务器命令
void recv_commands_thread(void* subscriber) {
    printf("Command receiver thread started\n");
    
    while (g_running) {
        char szBuf[1024] = { 0 };
        int ret = zmq_recv(subscriber, szBuf, sizeof(szBuf) - 1, 0);
        if (ret > 0) {
            printf("[RECV FROM SERVER] %s\n", szBuf);
            
            // 处理接收到的命令
            if (strstr(szBuf, "COMMAND") != NULL) {
                printf("  -> Processing command...\n");
            } else if (strstr(szBuf, "SERVER_DATA") != NULL) {
                printf("  -> Received server data\n");
            }
        } else {
            // 非阻塞接收,短暂延迟后继续
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    
    printf("Command receiver thread stopped\n");
}

int main() {
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    printf("Starting ZMQ Client (Bidirectional)...\n");
    printf("Client IP: 192.168.170.77\n");
    printf("Connecting to server: 192.168.170.53\n");
    printf("Port 5555: Receive commands from server\n");
    printf("Port 5556: Send data to server\n");

    void* context = zmq_ctx_new();
    assert(context != NULL);

    // 创建订阅者socket - 接收服务器命令
    void* command_subscriber = zmq_socket(context, ZMQ_SUB);
    assert(command_subscriber != NULL);
    
    int ret = zmq_connect(command_subscriber, "tcp://192.168.170.53:5555");
    assert(ret == 0);
    ret = zmq_setsockopt(command_subscriber, ZMQ_SUBSCRIBE, "", 0);
    assert(ret == 0);
    
    // 设置非阻塞接收
    int timeout = 100; // 100ms timeout
    zmq_setsockopt(command_subscriber, ZMQ_RCVTIMEO, &timeout, sizeof(timeout));
    
    printf("Command subscriber connected to tcp://192.168.170.53:5555\n");

    // 创建发布者socket - 发送数据到服务器
    void* data_publisher = zmq_socket(context, ZMQ_PUB);
    assert(data_publisher != NULL);
    
    ret = zmq_connect(data_publisher, "tcp://192.168.170.53:5556");
    assert(ret == 0);
    
    // 等待连接稳定(PUB-SUB模式需要)
    printf("Waiting for connection stabilization...\n");
    sleep(2);
    
    printf("Data publisher connected to tcp://192.168.170.53:5556\n");
    printf("Client started successfully!\n");

    // 启动命令接收线程
    std::thread command_thread(recv_commands_thread, command_subscriber);

    // 主循环 - 发送数据到服务器
    int sensor_count = 0;
    int heartbeat_count = 0;
    
    printf("Starting data transmission...\n");
    
    while (g_running) {
        // 发送传感器数据
        char sensor_buf[1024] = { 0 };
        snprintf(sensor_buf, sizeof(sensor_buf), "SENSOR_DATA_%d from client", sensor_count++);
        ret = zmq_send(data_publisher, sensor_buf, strlen(sensor_buf) + 1, 0);  // 现在 strlen 可以正常使用了
        printf("[SENT TO SERVER] %s\n", sensor_buf);
        
        // 发送心跳
        char heartbeat_buf[1024] = { 0 };
        snprintf(heartbeat_buf, sizeof(heartbeat_buf), "HEARTBEAT_%d", heartbeat_count++);
        ret = zmq_send(data_publisher, heartbeat_buf, strlen(heartbeat_buf) + 1, 0);
        printf("[SENT HEARTBEAT] %s\n", heartbeat_buf);
        
        sleep(2); // 每2秒发送一次
    }

    // 清理
    printf("Shutting down client...\n");
    g_running = false;
    if (command_thread.joinable()) {
        command_thread.join();
    }
    
    zmq_close(command_subscriber);
    zmq_close(data_publisher);
    zmq_ctx_destroy(context);
    
    printf("Client exited successfully.\n");
    return 0;
}

Cmake文件不变,然后make clean

make clean
cmake ..&&make
./zmp_client

Ctrl+C停止运行
如果启动上面线程就可以收到数据
在这里插入图片描述

Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ cmake ..&make
[1] 204384
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/Tronlong/mmcblk0p8/project_code/project/zmp_client/build
[ 25%] Building CXX object CMakeFiles/zmq_client.dir/src/main.cpp.o
[ 50%] Building CXX object CMakeFiles/zmq_client.dir/src/main1.cpp.o
[ 75%] Building CXX object CMakeFiles/zmq_client.dir/src/main2.cpp.o
[100%] Linking CXX executable zmq_client
[100%] Built target zmq_client
[1]+  Done                    cmake ..
Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ ./zmq_client 
Starting ZMQ Client (Bidirectional)...
Client IP: 192.168.170.77
Connecting to server: 192.168.170.53
Port 5555: Receive commands from server
Port 5556: Send data to server
Command subscriber connected to tcp://192.168.170.53:5555
Waiting for connection stabilization...
Data publisher connected to tcp://192.168.170.53:5556
Client started successfully!
Starting data transmission...
Command receiver thread started
[RECV FROM SERVER] Command 30
[RECV FROM SERVER] Command 31
[SENT TO SERVER] SENSOR_DATA_0 from client
[SENT HEARTBEAT] HEARTBEAT_0
[RECV FROM SERVER] Command 32
[RECV FROM SERVER] Command 33
[SENT TO SERVER] SENSOR_DATA_1 from client
[SENT HEARTBEAT] HEARTBEAT_1
[RECV FROM SERVER] Command 34
[RECV FROM SERVER] Command 35
[SENT TO SERVER] SENSOR_DATA_2 from client
[SENT HEARTBEAT] HEARTBEAT_2
[RECV FROM SERVER] Command 36
[RECV FROM SERVER] Command 37
[SENT TO SERVER] SENSOR_DATA_3 from client

两者通过两个 设备互通,这种方式实现了一个完全对等的双向通信架构
每个节点都是 “发布者 + 订阅者” 的组合体。


🔗 五、PAIR 模式(简洁双向)

PAIR 模式最接近传统的 Socket:

  • 一对一绑定
  • 全双工通信
  • 适合同机内控制指令/状态交换

🧭 Host(主节点)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "zmq.h"
#include <string>
#include <thread>
#include <atomic>
#include <iostream>
#include <chrono>
#include <conio.h>

std::atomic<bool> g_running{ true };

// 接收线程函数
void recv_thread(void* socket) {
    printf("Receive thread started\n");

    while (g_running) {
        char buffer[1024] = { 0 };
        int ret = zmq_recv(socket, buffer, sizeof(buffer) - 1, ZMQ_DONTWAIT);

        if (ret > 0) {
            printf("[RECV FROM CLIENT] %s\n", buffer);

            // 根据接收到的消息类型进行响应
            if (strstr(buffer, "SENSOR") != NULL) {
                // 收到传感器数据,发送确认
                const char* ack = "ACK_SENSOR_DATA";
                zmq_send(socket, ack, strlen(ack) + 1, 0);
                printf("[SENT TO CLIENT] %s\n", ack);
            }
            else if (strstr(buffer, "HEARTBEAT") != NULL) {
                // 收到心跳,发送响应
                const char* response = "HEARTBEAT_ACK";
                zmq_send(socket, response, strlen(response) + 1, 0);
                printf("[SENT TO CLIENT] %s\n", response);
            }
        }
        else if (ret == -1 && zmq_errno() != EAGAIN) {
            // 真正的错误
            printf("Receive error: %s\n", zmq_strerror(zmq_errno()));
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }

    printf("Receive thread stopped\n");
}

int main() {
    printf("Starting ZMQ PAIR Server...\n");
    printf("Server IP: 192.168.170.53\n");
    printf("Port 5555: PAIR communication with client\n");

    void* context = zmq_ctx_new();
    assert(context != NULL);

    // 创建 PAIR socket
    void* socket = zmq_socket(context, ZMQ_PAIR);
    assert(socket != NULL);

    int ret = zmq_bind(socket, "tcp://*:5555");
    assert(ret == 0);

    printf("PAIR socket bound to tcp://*:5555\n");
    printf("Waiting for client connection...\n");

    // 启动接收线程
    std::thread t(recv_thread, socket);

    // 主循环 - 发送命令和数据
    int command_count = 0;
    int data_count = 0;

    printf("\nServer ready! Press:\n");
    printf("  'C' - Send command\n");
    printf("  'D' - Send data\n");
    printf("  'Q' - Quit\n");

    while (g_running) {
        if (_kbhit()) {
            char key = _getch();

            if (key == 'q' || key == 'Q') {
                g_running = false;
                break;
            }
            else if (key == 'c' || key == 'C') {
                // 发送命令
                char command[256];
                snprintf(command, sizeof(command), "COMMAND_%d", command_count++);
                ret = zmq_send(socket, command, strlen(command) + 1, 0);
                printf("[SENT COMMAND] %s\n", command);
            }
            else if (key == 'd' || key == 'D') {
                // 发送数据
                char data[256];
                snprintf(data, sizeof(data), "DATA_%d", data_count++);
                ret = zmq_send(socket, data, strlen(data) + 1, 0);
                printf("[SENT DATA] %s\n", data);
            }
        }

        // 定期发送状态信息
        static auto last_status_time = std::chrono::steady_clock::now();
        auto now = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - last_status_time);

        if (elapsed.count() >= 5) {
            char status[256];
            snprintf(status, sizeof(status), "STATUS: Server running, commands: %d, data: %d",
                command_count, data_count);
            ret = zmq_send(socket, status, strlen(status) + 1, 0);
            printf("[SENT STATUS] %s\n", status);
            last_status_time = now;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    // 清理
    printf("Shutting down server...\n");
    g_running = false;
    if (t.joinable()) {
        t.join();
    }

    // 发送关闭消息
    const char* shutdown_msg = "SERVER_SHUTDOWN";
    zmq_send(socket, shutdown_msg, strlen(shutdown_msg) + 1, 0);

    zmq_close(socket);
    zmq_ctx_destroy(context);

    printf("Server exited successfully.\n");
    return 0;
}

如果启动下面线程就可以收到数据
在这里插入图片描述

在这里插入图片描述

Starting ZMQ PAIR Server...
Server IP: 192.168.170.53
Port 5555: PAIR communication with client
PAIR socket bound to tcp://*:5555
Waiting for client connection...

Server ready! Press:
  'C' - Send command
  'D' - Send data
  'Q' - Quit
Receive thread started
[SENT STATUS] STATUS: Server running, commands: 0, data: 0
[RECV FROM CLIENT] SENSOR_DATA_0: temp=33.30, hum=58.60
[SENT TO CLIENT] ACK_SENSOR_DATA
[RECV FROM CLIENT] HEARTBEAT_0
[SENT TO CLIENT] HEARTBEAT_ACK
[SENT STATUS] STATUS: Server running, commands: 0, data: 0
[RECV FROM CLIENT] SENSOR_DATA_1: temp=32.70, hum=51.50
[SENT TO CLIENT] ACK_SENSOR_DATA
[RECV FROM CLIENT] HEARTBEAT_1
[SENT TO CLIENT] HEARTBEAT_ACK
[RECV FROM CLIENT] SENSOR_DATA_2: temp=34.30, hum=53.50
[SENT TO CLIENT] ACK_SENSOR_DATA
[RECV FROM CLIENT] HEARTBEAT_2

⚓ Device(从节点)

#include <iostream>
#include <thread>
#include <cstdio>
#include <vector>
#include <cstring>
#include <ctime>
#include <atomic>
#include <csignal>
#include <cmath>
#include "zmq.hpp"

// 定义结构体
struct SensorData
{
    uint32_t sensor_id;
    float value;
    uint64_t timestamp;
};

struct ControlCommand
{
    uint32_t device_id;
    uint8_t command;
    uint32_t parameter;
};

// 退出标志
std::atomic<bool> running{true};

// 信号处理函数
void signal_handler(int signum)
{
    std::cout << "\nReceived signal " << signum << ", stopping..." << std::endl;
    running = false;
}

// 序列化函数模板
template <typename T>
std::vector<uint8_t> serialize_struct(const T &data)
{
    std::vector<uint8_t> buffer(sizeof(T));
    std::memcpy(buffer.data(), &data, sizeof(T));
    return buffer;
}

// 反序列化函数模板
template <typename T>
T deserialize_struct(const zmq::message_t &message)
{
    T data{};
    if (message.size() == sizeof(T))
    {
        std::memcpy(&data, message.data(), sizeof(T));
    }
    return data;
}

// 格式化时间戳
std::string format_timestamp(uint64_t timestamp)
{
    time_t t = static_cast<time_t>(timestamp);
    char buffer[20];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", localtime(&t));
    return std::string(buffer);
}

int main()
{
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    // 使用 PAIR 模式
    const auto socket_path = "/mnt/project/zmp_message/.pair_socket";
    
    zmq::context_t ctx(1);
    zmq::socket_t pair_socket(ctx, zmq::socket_type::pair);
    pair_socket.connect(std::string("ipc://") + socket_path);
    
    // 设置接收超时
    pair_socket.set(zmq::sockopt::rcvtimeo, 1000);

    std::cout << "Device PAIR started. Sending sensor data and receiving commands..." << std::endl;

    // 启动接收线程
    std::thread receiver([&]()
                         {
        while (true) {
            if (!running) {
                break;
            }
            try {
                zmq::message_t message;
                auto result = pair_socket.recv(message);
                
                if (result) {
                    // 判断消息类型
                    if (message.size() == sizeof(ControlCommand)) {
                        ControlCommand command = deserialize_struct<ControlCommand>(message);
                        std::cout << "[RECV COMMAND] Device ID: " << command.device_id 
                                  << ", Command: " << static_cast<int>(command.command)
                                  << ", Parameter: " << command.parameter << std::endl;
                                  
                        // 处理接收到的命令
                        switch(command.command) {
                            case 0:
                                std::cout << "  -> Executing START command" << std::endl;
                                break;
                            case 1:
                                std::cout << "  -> Executing STOP command" << std::endl;
                                break;
                            default:
                                std::cout << "  -> Executing UNKNOWN command" << std::endl;
                                break;
                        }
                    } else {
                        std::cout << "[RECV UNKNOWN] Size: " << message.size() << std::endl;
                    }
                }
            } catch (const zmq::error_t& e) {
                if (running && e.num() != EAGAIN) {
                    std::cerr << "Receive error: " << e.what() << std::endl;
                }
                break;
            }
        }
        std::cout << "Receiver thread exiting." << std::endl; });

    // 主循环发送传感器数据
    int count = 0;
    while (true)
    {
        if (!running) {
            break;
        }
        try
        {
            // 发送传感器数据
            SensorData sensor{
                static_cast<uint32_t>(count % 5),
                static_cast<float>(20.0 + 10.0 * sin(count * 0.5)), // 模拟传感器值
                static_cast<uint64_t>(std::time(nullptr))
            };
            
            auto sensor_data = serialize_struct(sensor);
            pair_socket.send(zmq::buffer(sensor_data), zmq::send_flags::none);
            
            std::cout << "[SENT SENSOR] ID: " << sensor.sensor_id 
                      << ", Value: " << sensor.value 
                      << ", Time: " << format_timestamp(sensor.timestamp) << std::endl;

            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            count++;
        }
        catch (const std::exception &e)
        {
            if (running) {
                std::cerr << "Send error: " << e.what() << std::endl;
            }
        }
    }

    // 清理资源
    running = false;
    if (receiver.joinable())
    {
        receiver.join();
    }

    std::cout << "Device PAIR exited." << std::endl;
    return 0;
}

Cmake文件不变,然后make clean

make clean
cmake ..&&make
./zmp_client

Ctrl+C停止运行
如果启动下面线程就可以收到数据
在这里插入图片描述

Tronlong@RK3576-Tronlong:~/mmcblk0p8/project_code/project/zmp_client/build$ ./zmq_client 
Starting ZMQ PAIR Client...
Client IP: 192.168.170.77
Connecting to server: 192.168.170.53:5555
PAIR socket connected to tcp://192.168.170.53:5555
Client started successfully!
Starting data transmission...
Receive thread started
[SENT SENSOR] SENSOR_DATA_0: temp=33.30, hum=58.60
[SENT HEARTBEAT] HEARTBEAT_0
[RECV FROM SERVER] STATUS: Server running, commands: 0, data: 0
  -> Server status update
[RECV FROM SERVER] ACK_SENSOR_DATA
  -> Processing data...
[RECV FROM SERVER] HEARTBEAT_ACK
  -> Received acknowledgment
[RECV FROM SERVER] STATUS: Server running, commands: 0, data: 0
  -> Server status update
[SENT SENSOR] SENSOR_DATA_1: temp=32.70, hum=51.50
[SENT HEARTBEAT] HEARTBEAT_1
[RECV FROM SERVER] ACK_SENSOR_DATA
  -> Processing data...
[RECV FROM SERVER] HEARTBEAT_ACK
  -> Received acknowledgment
[SENT SENSOR] SENSOR_DATA_2: temp=34.30, hum=53.50
[SENT HEARTBEAT] HEARTBEAT_2

这样可以通过 Ctrl+C 优雅退出,线程安全且无资源泄露。


这个支持断电重连,very nice😘😘😘

🧩 七、三种模式对比

模式类型 通信方向 特点 适用场景
PUB/SUB 单向 广播式,一对多 数据分发(日志、传感器)
双向 PUB/SUB 双向 灵活扩展,可多节点 主从控制、任务指令
PAIR 双向 一对一、简洁高效 控制与状态同步

🧱 八、总结

本文展示了 ZeroMQ 在同一设备上的三种通信实现方式

  1. 发布-订阅(PUB/SUB) —— 一对多信息分发
  2. 双向发布订阅(双节点互发) —— 双向协同通信
  3. 配对模式(PAIR) —— 简单高效的点对点交换

ZeroMQ 的设计使得这些模式都可以通过极少的代码完成,
并且支持无锁、异步、跨语言,非常适合在:

  • 🛥️ 无人船控制
  • 🤖 智能机器人
  • 🧩 模块化仿真系统
    等多进程通信场景中使用。

🧾 九、附录:参考文档


💡 提示:在 Linux 环境下运行 IPC 套接字时,请确保路径存在,并拥有读写权限。
若在 Windows 使用,请将下位机Ubuntu中下位机代码改为 "tcp://192.168.170.53:5555" 为自己的地址,TCP 模式。


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐