Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
cppzmq
https://github.com/zeromq/cppzmq
Admin
Header-only C++ binding for libzmq
Tokens:
35,358
Snippets:
393
Trust Score:
7.6
License:
MIT
Update:
1 month ago
Context
Chat
Benchmark
73.17
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Configure tests and examples Source: https://github.com/zeromq/cppzmq/blob/master/CMakeLists.txt Conditionally enables testing and example builds based on project options and C++ standard requirements. ```cmake option(CPPZMQ_BUILD_TESTS "Whether or not to build the tests" ON) if (CPPZMQ_BUILD_TESTS) enable_testing() add_subdirectory(tests) if (CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD EQUAL 98 AND CMAKE_CXX_STANDARD GREATER_EQUAL 11) add_subdirectory(examples) endif() endif() ``` -------------------------------- ### Install and export package configuration Source: https://github.com/zeromq/cppzmq/blob/master/CMakeLists.txt Configures and installs the necessary files for CMake package discovery and pkg-config support. ```cmake include(GNUInstallDirs) include(CMakePackageConfigHelpers) install(TARGETS cppzmq cppzmq-static EXPORT ${PROJECT_NAME}-targets) install(FILES ${CPPZMQ_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". set(CPPZMQ_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for cppzmqConfig.cmake") configure_file(libzmq-pkg-config/FindZeroMQ.cmake libzmq-pkg-config/FindZeroMQ.cmake COPYONLY) export(EXPORT ${PROJECT_NAME}-targets FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${CPPZMQ_CMAKECONFIG_INSTALL_DIR}) # Workaround until ARCH_INDEPENDENT flag can be used with cmake 3.14. # The ConigVersion.cmake file contains checks for the architecture is was # generated on, which can cause problems for header only libraries # used with e.g. the Conan package manager. Since it is header only we # can/should omit those checks. set(CPPZMQ_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) set(CMAKE_SIZEOF_VOID_P "") # a simple unset is not sufficient write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${CPPZMQ_VERSION} COMPATIBILITY AnyNewerVersion) set(CMAKE_SIZEOF_VOID_P ${CPPZMQ_SIZEOF_VOID_P}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cppzmq.pc.in ${CMAKE_CURRENT_BINARY_DIR}/cppzmq.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cppzmq.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${CPPZMQ_CMAKECONFIG_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${CPPZMQ_CMAKECONFIG_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libzmq-pkg-config/FindZeroMQ.cmake DESTINATION ${CPPZMQ_CMAKECONFIG_INSTALL_DIR}/libzmq-pkg-config) ``` -------------------------------- ### Build cppzmq via vcpkg Source: https://github.com/zeromq/cppzmq/blob/master/README.md Alternative installation method using the vcpkg package manager. ```bash git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh (bootstrap-vcpkg.bat for Powershell) ./vcpkg integrate install ./vcpkg install cppzmq ``` -------------------------------- ### Start a steerable ØMQ proxy Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-utilities.md Starts a proxy that can be controlled via a command socket. Send 'PAUSE' or 'RESUME' to the control socket to manage proxy state. ```cpp zmq::context_t ctx; zmq::socket_t frontend(ctx, zmq::socket_type::pull); zmq::socket_t backend(ctx, zmq::socket_type::push); zmq::socket_t control(ctx, zmq::socket_type::pull); frontend.bind("tcp://127.0.0.1:5555"); backend.bind("tcp://127.0.0.1:5556"); control.bind("inproc://proxy_control"); std::thread proxy_thread([&]() { zmq::proxy_steerable(zmq::socket_ref(frontend), zmq::socket_ref(backend), zmq::socket_ref(), zmq::socket_ref(control)); }); // ... pause proxy zmq::socket_t control_send(ctx, zmq::socket_type::push); control_send.connect("inproc://proxy_control"); control_send.send(zmq::str_buffer("PAUSE")); ``` -------------------------------- ### zmq::proxy_steerable Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-utilities.md Starts a steerable ØMQ proxy with a control socket for commands. ```APIDOC ## void proxy_steerable(socket_ref frontend, socket_ref backend, socket_ref capture, socket_ref control) ### Description Starts a steerable ØMQ proxy with a control socket for commands like PAUSE or RESUME. This function blocks. ### Parameters - **frontend** (socket_ref) - Required - Frontend socket - **backend** (socket_ref) - Required - Backend socket - **capture** (socket_ref) - Required - Capture socket (or empty ref) - **control** (socket_ref) - Required - Control socket for proxy commands ### Throws - **zmq::error_t** - On error ``` -------------------------------- ### Configure CMake for cppzmq Examples Source: https://github.com/zeromq/cppzmq/blob/master/examples/CMakeLists.txt Sets up the project, defines output directories according to GNU standards, and finds required dependencies. ```cmake cmake_minimum_required(VERSION 3.11 FATAL_ERROR) project(cppzmq-examples CXX) # place binaries and libraries according to GNU standards include(GNUInstallDirs) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) find_package(Threads) find_package(cppzmq) ``` -------------------------------- ### Get message options with get() Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-message.md Retrieves specific message option values such as ZMQ_MORE. ```cpp int more = msg.get(ZMQ_MORE); ``` -------------------------------- ### Build cppzmq via CMake Source: https://github.com/zeromq/cppzmq/blob/master/README.md Standard sequence of commands to clone, build, and install the cppzmq wrapper. ```bash 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 ``` -------------------------------- ### Build libzmq via CMake Source: https://github.com/zeromq/cppzmq/blob/master/README.md Standard sequence of commands to clone, build, and install the libzmq dependency. ```bash git clone https://github.com/zeromq/libzmq.git cd libzmq mkdir build cd build cmake .. sudo make -j4 install ``` -------------------------------- ### zmq::proxy Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-utilities.md Starts a ØMQ proxy connecting frontend and backend sockets. ```APIDOC ## void proxy(void *frontend, void *backend, void *capture) ### Description Starts a ØMQ proxy. The proxy connects a frontend socket to a backend socket, optionally capturing all messages. This function blocks until the proxy is terminated. ### Parameters - **frontend** (void*) - Required - Native frontend socket handle - **backend** (void*) - Required - Native backend socket handle - **capture** (void*) - Required - Native capture socket handle (or nullptr) ### Throws - **zmq::error_t** - On error ``` -------------------------------- ### monitor Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-monitor.md Starts monitoring a socket by creating an internal monitoring socket that receives events. ```APIDOC ## monitor(socket_ref sock, const char *addr, int events) ### Description Starts monitoring a socket, creating an internal monitoring socket that receives events. ### Parameters - **sock** (socket_ref / socket_t) - Required - Socket to monitor - **addr** (const char*) - Required - Endpoint for monitoring socket (typically inproc://) - **events** (int) - Optional (Default: ZMQ_EVENT_ALL) - Event mask (e.g., ZMQ_EVENT_CONNECTED, ZMQ_EVENT_DISCONNECTED) ### Throws - zmq::error_t on error ``` -------------------------------- ### Configure cppzmq socket options Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/configuration.md Demonstrates how to set and get various socket options such as linger, high water marks, timeouts, routing IDs, subscriptions, CURVE security, and TCP settings. ```cpp // Get/set linger sock.set(zmq::sockopt::linger, 100); int linger = sock.get(zmq::sockopt::linger); // High water marks sock.set(zmq::sockopt::rcvhwm, 5000); sock.set(zmq::sockopt::sndhwm, 5000); // Timeouts (in milliseconds) sock.set(zmq::sockopt::rcvtimeo, 5000); // 5 second receive timeout sock.set(zmq::sockopt::sndtimeo, 5000); // 5 second send timeout // Connect timeout sock.set(zmq::sockopt::connect_timeout, 3000); // 3 seconds // Routing ID sock.set(zmq::sockopt::routing_id, "my-client-id"); // Pub/Sub auto sub = zmq::socket_t(ctx, zmq::socket_type::sub); sub.set(zmq::sockopt::subscribe, ""); // Subscribe to all sub.set(zmq::sockopt::subscribe, "topic:"); // Subscribe to prefix // CURVE security zmq::socket_t secure_sock(ctx, zmq::socket_type::push); auto [pub, sec] = zmq::curve_keypair(); secure_sock.set(zmq::sockopt::curve_secretkey, sec); secure_sock.set(zmq::sockopt::curve_serverkey, server_public_key); // TCP settings sock.set(zmq::sockopt::tcp_keepalive, 1); sock.set(zmq::sockopt::tcp_keepalive_idle, 60); // Get last endpoint std::string endpoint = sock.get(zmq::sockopt::last_endpoint); ``` -------------------------------- ### get Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Retrieves the value of a context option. ```APIDOC ## int get(ctxopt option) ### Description Gets a context option value. ### Parameters - **option** (ctxopt) - Required - The context option to retrieve ### Returns - **int** - the option value ### Throws - `zmq::error_t` if the option cannot be retrieved ### Example ```cpp int threads = ctx.get(zmq::ctxopt::io_threads); ``` ``` -------------------------------- ### get Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Retrieves socket option values. ```APIDOC ## T get(sockopt::integral_option<Opt, T, BoolUnit>) ### Description Gets an integral socket option value. ### Parameters - **option** (sockopt::integral_option) - Required - The socket option ### Returns - T - the option value --- ## size_t get(sockopt::array_option<Opt, NullTerm>, mutable_buffer buf) / std::string get(..., size_t init_size) ### Description Gets a string or binary socket option. ### Parameters - **option** (sockopt::array_option) - Required - The socket option - **buf** (mutable_buffer) - Optional - Buffer to read into - **init_size** (size_t) - Optional - Initial string size (default 1024) ``` -------------------------------- ### CMake configuration for cppzmq project Source: https://github.com/zeromq/cppzmq/blob/master/demo/CMakeLists.txt Standard setup for a C++ project using cppzmq, including package discovery and test registration. ```cmake cmake_minimum_required(VERSION 3.0 FATAL_ERROR) project(cppzmq-demo CXX) find_package(cppzmq) enable_testing() add_executable( demo main.cpp ) target_link_libraries( demo cppzmq ) add_test( NAME demo COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/demo ) ``` -------------------------------- ### Register socket with active_poller_t Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-addon.md Example demonstrating how to register a socket for polling and handle incoming events. ```cpp zmq::active_poller_t poller; zmq::socket_t sock(ctx, zmq::socket_type::pull); sock.bind("tcp://127.0.0.1:5555"); poller.add(sock, ZMQ_POLLIN, [&](short revents) { if (revents & ZMQ_POLLIN) { zmq::message_t msg; sock.recv(msg); std::cout << "Received: " << std::string(msg.data<char>(), msg.size()) << "\n"; } }); // Wait for events (blocking) poller.wait(std::chrono::milliseconds(1000)); ``` -------------------------------- ### Start a ØMQ proxy Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-utilities.md Connects a frontend socket to a backend socket. This function blocks the calling thread until the proxy is terminated. ```cpp zmq::context_t ctx; zmq::socket_t frontend(ctx, zmq::socket_type::pull); zmq::socket_t backend(ctx, zmq::socket_type::push); frontend.bind("tcp://127.0.0.1:5555"); backend.bind("tcp://127.0.0.1:5556"); // Run in separate thread std::thread proxy_thread([&]() { zmq::proxy(frontend.handle(), backend.handle(), nullptr); }); // ... later, terminate proxy ``` -------------------------------- ### Get context option Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Retrieves the current integer value of a specified context option. ```cpp int threads = ctx.get(zmq::ctxopt::io_threads); ``` -------------------------------- ### Get native context handle Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Retrieves the underlying native ZeroMQ context pointer for C API interoperability. ```cpp void *native_ctx = ctx.handle(); ``` -------------------------------- ### Get String or Binary Socket Option Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Retrieves a string or binary socket option into a buffer or as a std::string. ```cpp char endpoint[256]; sock.get(zmq::sockopt::last_endpoint, zmq::buffer(endpoint)); std::string endpoint = sock.get(zmq::sockopt::last_endpoint); ``` -------------------------------- ### Monitor socket events Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-monitor.md Starts monitoring a socket by creating an internal monitoring socket. Requires an endpoint address, typically using the inproc transport. ```cpp void monitor(socket_ref sock, const char *addr, int events = ZMQ_EVENT_ALL) void monitor(socket_t &sock, const char *addr, int events = ZMQ_EVENT_ALL) void monitor(socket_t &&sock, const char *addr, int events = ZMQ_EVENT_ALL) ``` ```cpp zmq::context_t ctx; zmq::socket_t sock(ctx, zmq::socket_type::push); zmq::monitor_t monitor; monitor.monitor(sock, "inproc://monitor", ZMQ_EVENT_ALL); sock.connect("tcp://127.0.0.1:5555"); // Monitor events in separate thread std::thread monitor_thread([&]() { while (true) { int value; auto event = monitor.next_event(value); if (event.event == ZMQ_EVENT_CONNECTED) { std::cout << "Socket connected\n"; } } }); ``` -------------------------------- ### Configure ZeroMQ Context Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/configuration.md Demonstrates initializing a context with default settings, custom parameters, and advanced configuration using the set() method. ```cpp // Default context zmq::context_t ctx; // Custom I/O threads and max sockets zmq::context_t ctx(4, 1024); // 4 threads, 1024 max sockets // Advanced configuration via set() zmq::context_t ctx; ctx.set(zmq::ctxopt::io_threads, 8); ctx.set(zmq::ctxopt::max_sockets, 2048); ctx.set(zmq::ctxopt::max_msgsz, 1024 * 1024 * 100); // 100MB ``` -------------------------------- ### Create Socket and Connect/Bind Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Instantiate a socket and establish communication endpoints using bind or connect. ```cpp zmq::socket_t socket(ctx, zmq::socket_type::push); socket.bind("tcp://127.0.0.1:5555"); // Server mode socket.connect("tcp://127.0.0.1:5555"); // Client mode // Get actual endpoint (for wildcard port) std::string ep = socket.get(zmq::sockopt::last_endpoint); ``` -------------------------------- ### Basic ZeroMQ Push Socket Usage Source: https://github.com/zeromq/cppzmq/blob/master/README.md Demonstrates initializing a context, creating a push socket, binding to an in-process endpoint, and sending a message. ```c++ #include <zmq.hpp> int main() { zmq::context_t ctx; zmq::socket_t sock(ctx, zmq::socket_type::push); sock.bind("inproc://test"); sock.send(zmq::str_buffer("Hello, world"), zmq::send_flags::dontwait); } ``` -------------------------------- ### Basic Socket Monitoring in C++ Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-monitor.md Demonstrates initializing a monitor on a socket and polling for events in a separate thread. ```cpp zmq::context_t ctx; zmq::socket_t sock(ctx, zmq::socket_type::push); zmq::monitor_t monitor; monitor.monitor(sock, "inproc://monitor"); sock.connect("tcp://127.0.0.1:5555"); // Poll for events std::thread poll_thread([&]() { int value; while (true) { try { auto event = monitor.next_event(value, std::chrono::milliseconds(1000)); std::cout << "Event: " << event.event << ", value: " << value << "\n"; } catch (const zmq::error_t &e) { break; } } }); ``` -------------------------------- ### Initialize context and sockets Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Create a ZeroMQ context to manage I/O threads and instantiate specific socket types. ```cpp // Create context (thread pool for I/O) zmq::context_t ctx; // Create different socket types zmq::socket_t push_socket(ctx, zmq::socket_type::push); zmq::socket_t pull_socket(ctx, zmq::socket_type::pull); zmq::socket_t pub_socket(ctx, zmq::socket_type::pub); zmq::socket_t sub_socket(ctx, zmq::socket_type::sub); // With custom I/O threads and max sockets zmq::context_t advanced_ctx(4, 1024); // 4 threads, 1024 max sockets ``` -------------------------------- ### get(int option_) Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-message.md Retrieves a message option value. ```APIDOC ## int get(int option_) const ### Description Gets a message option value. Returns the value or writes to optval_. ### Parameters - **option_** (int) - Required - Message option constant (ZMQ_MORE, etc.) - **optval_** (int*) - Optional - Pointer to store value (second overload) ### Returns int — option value ``` -------------------------------- ### Initialize default context_t Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Constructor signature and usage for creating a context with default settings. ```cpp context_t() ``` ```cpp zmq::context_t ctx; // Create default context ``` -------------------------------- ### Create a context and socket Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Initializes a ZeroMQ context and a push socket. Requires including zmq.hpp. ```cpp #include <zmq.hpp> zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::push); ``` -------------------------------- ### Create and Configure Context Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Initialize a ZeroMQ context with default or custom I/O thread and socket limits. ```cpp zmq::context_t ctx; // 1 I/O thread, default settings // Or with custom config zmq::context_t ctx(4, 1024); // 4 I/O threads, 1024 max sockets ctx.set(zmq::ctxopt::max_msgsz, 1024 * 1024 * 100); // 100MB max ``` -------------------------------- ### Get Integral Socket Option Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Retrieves the current value of an integral socket option. ```cpp int linger = sock.get(zmq::sockopt::linger); int hwm = sock.get(zmq::sockopt::rcvhwm); ``` -------------------------------- ### Implement Fair Queuing with PUSH Sockets Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/messaging-patterns.md Demonstrates how multiple producers distribute messages to consumers using round-robin fair queuing. ```cpp // Multiple producers push to same socket socket1.send(zmq::str_buffer("from producer 1")); socket2.send(zmq::str_buffer("from producer 2")); socket3.send(zmq::str_buffer("from producer 3")); // Multiple consumers pull fairly // consumer1 gets msg from socket1 // consumer2 gets msg from socket2 // consumer3 gets msg from socket3 // consumer1 gets msg from socket1 again (round-robin) ``` -------------------------------- ### Get native socket handle Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-monitor.md Retrieves the underlying native ZeroMQ socket pointer. ```cpp void *handle() noexcept const void *handle() const noexcept ``` ```cpp void *native_monitor = monitor.handle(); ``` -------------------------------- ### Initialize custom context_t Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Constructor signature and usage for creating a context with specific I/O thread counts and socket limits. ```cpp explicit context_t(int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT) ``` ```cpp zmq::context_t ctx(4, 1024); // 4 I/O threads, 1024 max sockets ``` -------------------------------- ### handle Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Returns the underlying native ZeroMQ context pointer. ```APIDOC ## void *handle() noexcept ### Description Returns the underlying native ZeroMQ context pointer. Use this only when interfacing with the C API. ### Returns - **void*** - pointer to the native zmq_ctx_t ### Example ```cpp void *native_ctx = ctx.handle(); ``` ``` -------------------------------- ### Implement an Echo Server with cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Demonstrates a basic REP socket server that binds to a TCP address and echoes received messages back to the client. ```cpp #include <zmq.hpp> #include <iostream> #include <string> int main() { try { zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::rep); socket.bind("tcp://127.0.0.1:5555"); std::cout << "Echo server listening on tcp://127.0.0.1:5555\n"; zmq::message_t request; while (true) { socket.recv(request); std::string msg(request.data<char>(), request.size()); std::cout << "Received: " << msg << "\n"; // Echo back socket.send(zmq::buffer(request.data(), request.size())); } } catch (const zmq::error_t &e) { std::cerr << "Error: " << e.what() << "\n"; return 1; } return 0; } ``` -------------------------------- ### Configure cppzmq project and dependencies Source: https://github.com/zeromq/cppzmq/blob/master/CMakeLists.txt Initializes the project, sets up the module path, and attempts to locate the ZeroMQ dependency using CMake packages or pkg-config. ```cmake cmake_minimum_required(VERSION 3.11) list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include (DetectCPPZMQVersion) project(cppzmq VERSION ${DETECTED_CPPZMQ_VERSION}) if (NOT TARGET libzmq AND NOT TARGET libzmq-static) find_package(ZeroMQ QUIET) # libzmq autotools install: fallback to pkg-config if(NOT ZeroMQ_FOUND) message(STATUS "CMake libzmq package not found, trying again with pkg-config (normal install of zeromq)") list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/libzmq-pkg-config) find_package(ZeroMQ REQUIRED) endif() # TODO "REQUIRED" above should already cause a fatal failure if not found, but this doesn't seem to work if(NOT ZeroMQ_FOUND) message(FATAL_ERROR "ZeroMQ was not found, neither as a CMake package nor via pkg-config") endif() if (ZeroMQ_FOUND AND NOT (TARGET libzmq OR TARGET libzmq-static)) message(FATAL_ERROR "ZeroMQ version not supported!") endif() endif() ``` -------------------------------- ### Define ctxopt enumeration Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/types.md Context options for configuration, used with context_t::set() and context_t::get(). ```cpp enum class ctxopt { #ifdef ZMQ_BLOCKY blocky = ZMQ_BLOCKY, #endif #ifdef ZMQ_IO_THREADS io_threads = ZMQ_IO_THREADS, #endif #ifdef ZMQ_THREAD_SCHED_POLICY thread_sched_policy = ZMQ_THREAD_SCHED_POLICY, #endif #ifdef ZMQ_THREAD_PRIORITY thread_priority = ZMQ_THREAD_PRIORITY, #endif #ifdef ZMQ_THREAD_AFFINITY_CPU_ADD thread_affinity_cpu_add = ZMQ_THREAD_AFFINITY_CPU_ADD, #endif #ifdef ZMQ_THREAD_AFFINITY_CPU_REMOVE thread_affinity_cpu_remove = ZMQ_THREAD_AFFINITY_CPU_REMOVE, #endif #ifdef ZMQ_THREAD_NAME_PREFIX thread_name_prefix = ZMQ_THREAD_NAME_PREFIX, #endif #ifdef ZMQ_MAX_MSGSZ max_msgsz = ZMQ_MAX_MSGSZ, #endif #ifdef ZMQ_ZERO_COPY_RECV zero_copy_recv = ZMQ_ZERO_COPY_RECV, #endif #ifdef ZMQ_MAX_SOCKETS max_sockets = ZMQ_MAX_SOCKETS, #endif #ifdef ZMQ_SOCKET_LIMIT socket_limit = ZMQ_SOCKET_LIMIT, #endif #ifdef ZMQ_IPV6 ipv6 = ZMQ_IPV6, #endif #ifdef ZMQ_MSG_T_SIZE msg_t_size = ZMQ_MSG_T_SIZE #endif }; ``` -------------------------------- ### Initialize a socket with a context Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Creates a socket within a provided ZeroMQ context using a specific socket type. ```cpp zmq::context_t ctx; zmq::socket_t sock(ctx, zmq::socket_type::push); ``` -------------------------------- ### context_t() Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Constructor to create a new ZeroMQ context with default settings. ```APIDOC ## context_t() ### Description Creates a new ZeroMQ context with default settings (1 I/O thread, default maximum sockets). ### Parameters - None ### Returns A new context_t object ### Throws zmq::error_t if context creation fails ### Example ```cpp zmq::context_t ctx; // Create default context ``` ``` -------------------------------- ### Polling and Monitoring Sockets Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Demonstrates how to poll multiple sockets using arrays or vectors and how to monitor socket events. ```cpp // Simple polling with array zmq::pollitem_t items[] = { { socket1.handle(), 0, ZMQ_POLLIN, 0 }, { socket2.handle(), 0, ZMQ_POLLIN, 0 } }; int n = zmq::poll(items, 2, std::chrono::milliseconds(1000)); if (n > 0) { if (items[0].revents & ZMQ_POLLIN) { zmq::message_t msg; socket1.recv(msg); } if (items[1].revents & ZMQ_POLLIN) { zmq::message_t msg; socket2.recv(msg); } } // Polling with vector std::vector<zmq::pollitem_t> items = { { socket1.handle(), 0, ZMQ_POLLIN, 0 }, { socket2.handle(), 0, ZMQ_POLLIN, 0 } }; zmq::poll(items, std::chrono::milliseconds(1000)); // Monitor socket events zmq::monitor_t monitor; monitor.monitor(socket, "inproc://monitor"); int value; auto event = monitor.next_event(value, std::chrono::milliseconds(1000)); if (event.event == ZMQ_EVENT_CONNECTED) { std::cout << "Socket connected\n"; } ``` -------------------------------- ### Include cppzmq Headers Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Include the primary header and optional addon functions. Ensure the project is linked against libzmq. ```cpp #include <zmq.hpp> #include <zmq_addon.hpp> // Optional: for addon functions // Must link against libzmq // g++ -o myapp myapp.cpp -lzmq ``` -------------------------------- ### Initialize a socket with a moved context Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Creates a socket while moving ownership of the context into the socket object. ```cpp zmq::socket_t sock(zmq::context_t(), zmq::socket_type::pull); ``` -------------------------------- ### Manage resources with RAII Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Use zmq::context_t and zmq::socket_t to automatically manage the lifecycle of ZeroMQ resources. ```cpp { zmq::context_t ctx; // Creates context zmq::socket_t sock(ctx, zmq::socket_type::push); // Creates socket sock.bind("tcp://127.0.0.1:5555"); } // ctx and sock destroyed, resources freed automatically ``` -------------------------------- ### Include necessary headers Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Standard headers required for basic cppzmq functionality and addon features. ```cpp #include <zmq.hpp> #include <zmq_addon.hpp> // For addon functions #include <iostream> #include <string> #include <vector> #include <thread> ``` -------------------------------- ### Handle multi-part messages with cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Shows how to send and receive multi-part messages using the addon utility functions or manual flag-based control. ```cpp // Send multi-part using addon std::array<zmq::const_buffer, 3> parts = { zmq::str_buffer("frame1"), zmq::str_buffer("frame2"), zmq::str_buffer("frame3") }; zmq::send_multipart(socket, parts); // Receive multi-part using addon std::vector<zmq::message_t> messages; auto result = zmq::recv_multipart(socket, std::back_inserter(messages)); if (result) { std::cout << "Received " << *result << " parts\n"; for (size_t i = 0; i < messages.size(); ++i) { std::cout << "Part " << i << ": " << std::string(messages[i].data<char>(), messages[i].size()) << "\n"; } } // Manual multi-part (for more control) socket.send(zmq::str_buffer("header"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("body"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("trailer")); zmq::message_t msg; while (true) { socket.recv(msg); std::cout << std::string(msg.data<char>(), msg.size()) << "\n"; if (!msg.more()) break; } ``` -------------------------------- ### socket_t Constructors Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Methods to initialize a new ZeroMQ socket within a context. ```APIDOC ## socket_t() ### Description Creates an empty socket with no handle. Must be assigned a valid socket later. ## socket_t(context_t&, socket_type) ### Description Creates a new socket of the specified type within a context. ### Parameters - **ctx** (context_t&) - Required - The ZeroMQ context - **type** (socket_type) - Required - The socket type (REQ, REP, PUB, SUB, etc.) ## socket_t(context_t&&, socket_type) ### Description Creates a new socket within a context, moving the context into the socket. The socket takes ownership of the context's lifetime. ``` -------------------------------- ### Manage Context and Socket Shutdown Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Handle resource cleanup using manual socket closing, context shutdown, or RAII patterns. ```cpp // Graceful shutdown void shutdown_gracefully(zmq::context_t &ctx) { // Close all sockets socket1.close(); socket2.close(); // Terminate context (blocks until all sockets closed) ctx.close(); } // Or shutdown then close void force_shutdown(zmq::context_t &ctx) { // Interrupt blocking operations ctx.shutdown(); // Then close ctx.close(); } // With RAII (automatic) { zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::push); // ... } // Automatically cleaned up on scope exit ``` -------------------------------- ### Implement High-Level Convenience Functions Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Simplify common patterns like multi-part message sending using addon functions. ```cpp // Multi-part convenience std::array<zmq::const_buffer, 2> parts = { zmq::str_buffer("header"), zmq::str_buffer("body") }; zmq::send_multipart(sock, parts); // vs. manual send with SNDMORE flags ``` -------------------------------- ### Pass sockets to functions using socket_ref Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Demonstrates how to write functions that accept both owning and non-owning socket types via implicit conversion. ```cpp void process_socket(zmq::socket_ref s) { // Works with both socket_t and socket_ref zmq::message_t msg; s.recv(msg); s.send(msg); } zmq::socket_t sock(ctx, zmq::socket_type::push); process_socket(sock); // Implicit conversion zmq::socket_ref ref = sock; process_socket(ref); // Explicit reference ``` -------------------------------- ### Request-Reply Pattern Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Shows the implementation of a basic server and client using the REQ/REP pattern. ```cpp // Server zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::rep); socket.bind("tcp://127.0.0.1:5555"); zmq::message_t request; while (true) { socket.recv(request); std::cout << "Request: " << std::string(request.data<char>(), request.size()) << "\n"; socket.send(zmq::str_buffer("Reply")); } // Client zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::req); socket.connect("tcp://127.0.0.1:5555"); socket.send(zmq::str_buffer("Request")); zmq::message_t reply; socket.recv(reply); std::cout << "Reply: " << std::string(reply.data<char>(), reply.size()) << "\n"; ``` -------------------------------- ### Default Constructor Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-message.md Creates an empty message with zero size. ```cpp message_t() noexcept ``` ```cpp zmq::message_t msg; ``` -------------------------------- ### Implement Pub-Sub Pattern in cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Demonstrates a publisher binding to an address and a subscriber connecting to receive filtered messages. ```cpp // Publisher zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::pub); socket.bind("tcp://127.0.0.1:5555"); // Wait for subscribers std::this_thread::sleep_for(std::chrono::milliseconds(100)); for (int i = 0; i < 10; ++i) { socket.send(zmq::str_buffer("news"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("update " + std::to_string(i))); } // Subscriber zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::sub); socket.connect("tcp://127.0.0.1:5555"); socket.set(zmq::sockopt::subscribe, "news"); zmq::message_t topic, content; while (true) { socket.recv(topic); socket.recv(content); std::cout << "Topic: " << std::string(topic.data<char>(), topic.size()) << ", Content: " << std::string(content.data<char>(), content.size()) << "\n"; } ``` -------------------------------- ### Send and receive messages Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Demonstrates basic synchronous message transmission and reception using a socket. ```cpp socket.send(zmq::str_buffer("hello")); zmq::message_t msg; socket.recv(msg); ``` -------------------------------- ### Send data using buffers Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-socket.md Demonstrates sending data with standard buffers, including multi-part messages and non-blocking operations. ```cpp zmq::socket_t sock(ctx, zmq::socket_type::push); sock.send(zmq::str_buffer("hello")); // With flags sock.send(zmq::str_buffer("part1"), zmq::send_flags::sndmore); sock.send(zmq::str_buffer("part2")); // Non-blocking auto result = sock.send(zmq::str_buffer("msg"), zmq::send_flags::dontwait); if (result) { // Sent successfully } ``` -------------------------------- ### Implement a SUB socket in cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/messaging-patterns.md Initializes a subscriber socket, connects to the publisher, and sets a subscription filter for the 'news' topic. ```cpp zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::sub); socket.connect("tcp://127.0.0.1:5555"); // Subscribe to "news" topic socket.set(zmq::sockopt::subscribe, "news"); zmq::message_t topic, message; while (true) { socket.recv(topic); socket.recv(message); std::cout << "Topic: " << std::string(topic.data<char>(), topic.size()) << ", Message: " << std::string(message.data<char>(), message.size()) << "\n"; } ``` -------------------------------- ### Implement a PUB socket in cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/messaging-patterns.md Initializes a publisher socket and binds it to a TCP address. Includes a sleep delay to ensure subscribers have time to connect before message transmission begins. ```cpp zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::pub); socket.bind("tcp://127.0.0.1:5555"); // Allow time for subscribers to connect std::this_thread::sleep_for(std::chrono::milliseconds(100)); for (int i = 0; i < 100; ++i) { // Send to topic "news" socket.send(zmq::str_buffer("news"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("message " + std::to_string(i))); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } ``` -------------------------------- ### Implement Pipeline Pattern with PUSH and PULL Sockets Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/messaging-patterns.md The producer uses a PUSH socket to distribute tasks, while the consumer uses a PULL socket to collect them. Messages are queued if no consumer is available. ```cpp zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::push); socket.bind("tcp://127.0.0.1:5555"); for (int i = 0; i < 100; ++i) { std::string msg = "task " + std::to_string(i); socket.send(zmq::str_buffer(msg)); } ``` ```cpp zmq::context_t ctx; zmq::socket_t socket(ctx, zmq::socket_type::pull); socket.connect("tcp://127.0.0.1:5555"); zmq::message_t message; while (true) { socket.recv(message); std::cout << "Task: " << std::string(message.data<char>(), message.size()) << "\n"; } ``` -------------------------------- ### handle Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-monitor.md Returns the underlying native ZeroMQ socket pointer. ```APIDOC ## handle() ### Description Returns the underlying native ZeroMQ socket pointer for the monitoring socket. ### Returns - void* - pointer to native zmq_socket_t ``` -------------------------------- ### Integrate with CMake Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Use find_package to locate the library and link it to the target application. ```cmake find_package(cppzmq) target_link_libraries(myapp cppzmq) ``` -------------------------------- ### Configure Secure Communication Socket Options Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/configuration.md Generate CURVE keypairs and apply secret and server keys to the socket. ```cpp auto [pub, sec] = zmq::curve_keypair(); sock.set(zmq::sockopt::curve_secretkey, sec); sock.set(zmq::sockopt::curve_serverkey, server_pub); ``` -------------------------------- ### set Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-context.md Sets a context option such as io_threads or max_sockets. ```APIDOC ## void set(ctxopt option, int optval) ### Description Sets a context option. Valid options include `ctxopt::io_threads`, `ctxopt::max_sockets`, and others depending on libzmq version. ### Parameters - **option** (ctxopt) - Required - The context option to set - **optval** (int) - Required - The value to set ### Returns - **void** ### Throws - `zmq::error_t` if the option cannot be set ### Example ```cpp ctx.set(zmq::ctxopt::io_threads, 2); ``` ``` -------------------------------- ### Utilize Type-Safe Wrappers Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Use enums and type-safe options to replace magic constants for socket configuration. ```cpp // Instead of: // zmq_setsockopt(sock, ZMQ_LINGER, &val, sizeof(int)); // Use: sock.set(zmq::sockopt::linger, 100); // Type-safe, clear intent // Socket type instead of constant zmq::socket_t sock(ctx, zmq::socket_type::push); // Clear socket purpose ``` -------------------------------- ### Send Multi-Part Messages Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/messaging-patterns.md Demonstrates manual multi-part transmission using SNDMORE flags and the simplified send_multipart addon function. ```cpp // Manual approach socket.send(zmq::str_buffer("header"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("body"), zmq::send_flags::sndmore); socket.send(zmq::str_buffer("footer")); // No SNDMORE flag // Using addon function std::array<zmq::const_buffer, 3> parts = { zmq::str_buffer("header"), zmq::str_buffer("body"), zmq::str_buffer("footer") }; zmq::send_multipart(socket, parts); ``` -------------------------------- ### Configure Socket Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/README.md Adjust socket options such as timeouts, high-water marks, and subscriptions. ```cpp socket.set(zmq::sockopt::linger, 100); // Linger 100ms on close socket.set(zmq::sockopt::rcvtimeo, 5000); // 5 second receive timeout socket.set(zmq::sockopt::rcvhwm, 1000); // Queue max 1000 messages socket.set(zmq::sockopt::subscribe, "topic"); // Pub/Sub subscription int linger = socket.get(zmq::sockopt::linger); ``` -------------------------------- ### buffer Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-message.md Creates a buffer wrapper for raw memory. ```APIDOC ## buffer ### Description Creates a buffer wrapper for raw memory. ### Signature `inline const_buffer buffer(const void *ptr, size_t size)` `inline mutable_buffer buffer(void *ptr, size_t size)` ### Example ```cpp char data[256]; zmq::message_t msg; sock.recv(msg); // Use msg.data() for content ``` ``` -------------------------------- ### Initialize an owning socket_t Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Creates a socket that manages its own lifecycle and closes upon destruction. ```cpp zmq::socket_t sock(ctx, zmq::socket_type::push); // Owns the underlying socket // Closes socket on destruction // Cannot be copied (move-only) ``` -------------------------------- ### Create and resize buffers with zmq::buffer Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-utilities.md Wraps memory regions into buffer objects for socket operations. Use the overload with an existing buffer to create a view of a specific size. ```cpp char data[256]; auto buf = zmq::buffer(data, 256); sock.recv(buf); // Resize buffer auto partial = zmq::buffer(buf, 100); // 100 bytes starting at buf.data() ``` -------------------------------- ### Map Raw C API Functions in cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/class-hierarchy.md Direct 1:1 mapping of libzmq C functions to C++ objects. ```cpp zmq::context_t ctx; // Wraps zmq_ctx_new() zmq::socket_t sock(...); // Wraps zmq_socket() sock.bind(...); // Wraps zmq_bind() sock.send(...); // Wraps zmq_send() sock.recv(...); // Wraps zmq_recv() ``` -------------------------------- ### Integrate cppzmq in CMakeLists.txt Source: https://github.com/zeromq/cppzmq/blob/master/README.md Configuration lines to find and link the cppzmq library in a CMake project. ```cmake #find cppzmq wrapper, installed by make of cppzmq find_package(cppzmq) target_link_libraries(*Your Project Name* cppzmq) # Or use static library to link target_link_libraries(*Your Project Name* cppzmq-static) ``` -------------------------------- ### Implement CURVE Security Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Generate keypairs and configure server and client sockets for encrypted communication. ```cpp // Generate keypair auto [public_key, secret_key] = zmq::curve_keypair(); std::cout << "Public: " << public_key << "\n"; std::cout << "Secret: " << secret_key << "\n"; // Server zmq::socket_t server(ctx, zmq::socket_type::rep); server.set(zmq::sockopt::curve_server, true); server.set(zmq::sockopt::curve_secretkey, server_secret_key); server.bind("tcp://127.0.0.1:5555"); // Client zmq::socket_t client(ctx, zmq::socket_type::req); client.set(zmq::sockopt::curve_secretkey, client_secret_key); client.set(zmq::sockopt::curve_serverkey, server_public_key); client.connect("tcp://127.0.0.1:5555"); client.send(zmq::str_buffer("Secure message")); ``` -------------------------------- ### Catch zmq::error_t exceptions Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/errors.md Standard pattern for catching ZeroMQ errors using the default constructor. ```cpp try { // operation that fails } catch (const zmq::error_t &e) { // e captures the error that occurred } ``` -------------------------------- ### Configure Low Latency Socket Options Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/configuration.md Minimize buffering to reduce latency in time-sensitive messaging. ```cpp sock.set(zmq::sockopt::linger, 0); sock.set(zmq::sockopt::rcvhwm, 1); sock.set(zmq::sockopt::sndhwm, 1); ``` -------------------------------- ### Receive messages with cppzmq Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/quick-start.md Demonstrates various methods for receiving data, including direct message objects, fixed-size buffers, non-blocking calls, and checking for multi-part message segments. ```cpp // Receive into message object zmq::message_t msg; socket.recv(msg); std::string content(msg.data<char>(), msg.size()); // Receive into buffer char buffer[256]; auto result = socket.recv(zmq::buffer(buffer, 256)); if (result) { if (result->truncated()) { std::cout << "Message was truncated (full size: " << result->untruncated_size << ")\n"; } std::cout << "Received " << result->size << " bytes\n"; } // Non-blocking receive zmq::message_t msg; auto result = socket.recv(msg, zmq::recv_flags::dontwait); if (!result) { std::cout << "No message available\n"; } else { std::cout << "Received " << *result << " bytes\n"; } // Check for more parts zmq::message_t part1, part2; socket.recv(part1); if (part1.more()) { socket.recv(part2); } ``` -------------------------------- ### Configure Environment Variables Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/configuration.md Set environment variables to influence libzmq global behavior. Direct use is discouraged in favor of explicit code-based configuration. ```bash export ZMQ_RCVMORE=1 ``` ```bash export ZMQ_BLOCKY=0 ``` ```bash export ZMQ_ZERO_COPY_RECV=1 ``` -------------------------------- ### handle() Source: https://github.com/zeromq/cppzmq/blob/master/_autodocs/api-reference-message.md Returns the underlying native zmq_msg_t pointer for C API interoperability. ```APIDOC ## void *handle() noexcept ### Description Returns the underlying native zmq_msg_t pointer for C API interoperability. ### Returns void* — pointer to native zmq_msg_t ```