要使ZMQ_RADIO / ZMQ_DISH正常工作,我需要做什么?

时间:2017-07-17 20:56:31

标签: c++ linux zeromq

我正在尝试使用ZMQ草案规范ZMQ_RADIOZMQ_DISH。我使用CMake ExternalProject和标记ENABLE_DRAFTS=ON构建了libzmq和cppzmq,并验证它是使用zmq_has()函数使用草稿构建的。我修改了标准hello world example以使用收音机和碟子而无法让他们说话。我也遇到了ZMQ_RADIOZMQ_DISH未定义的编译错误。我手动定义它们并且它编译但是我从来没有得到实际连接所以看起来其他的东西是错误的。

这是我的代码:

的CMakeLists.txt

cmake_minimum_required(VERSION 2.8.11)
project(zmq_udp)

include(ExternalProject)

ExternalProject_Add(libzmq
    GIT_REPOSITORY https://github.com/zeromq/libzmq
    GIT_TAG master
    CMAKE_ARGS 
      -DENABLE_DRAFTS=ON
      -DWITH_PERF_TOOL=OFF 
      -DZMQ_BUILD_TESTS=OFF 
      -DENABLE_CPACK=OFF
      -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/zmq
      -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/zmq/lib
      -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
      -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
      -DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}
)

ExternalProject_Add(cppzmq
    GIT_REPOSITORY https://github.com/zeromq/cppzmq
    GIT_TAG master
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ""
    INSTALL_COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/zmq.hpp ${CMAKE_BINARY_DIR}/zmq/include/zmq.hpp
    TEST_COMMAND ""
)

add_dependencies(cppzmq libzmq)

set(ZEROMQ_LIBNAME "libzmq.so")
set(ZEROMQ_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/zmq/include)
set(ZEROMQ_LIBRARIES ${CMAKE_BINARY_DIR}/zmq/lib/${ZEROMQ_LIBNAME})

include_directories(${ZEROMQ_INCLUDE_DIRS})

add_executable(server server.cpp)
add_executable(client client.cpp)
add_dependencies(server cppzmq)
add_dependencies(client cppzmq)
target_link_libraries(server ${ZEROMQ_LIBRARIES})
target_link_libraries(client ${ZEROMQ_LIBRARIES})

server.cpp

#include <zmq.hpp>
#include <string>
#include <iostream>

#define ZMQ_DISH 15

int main ()
{
    std::cout << zmq_has("draft") << std::endl;

    zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_DISH);
    socket.bind ("udp://127.0.0.1:5555");

    while (true)
    {
        zmq::message_t request;

        socket.recv (&request);
        std::cout << "Received Hello" << std::endl;
    }

    return 0;
}

client.cpp

#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>

#define ZMQ_RADIO 14

int main ()
{
    zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_RADIO);

    std::cout << "Connecting to hello world server…" << std::endl;
    socket.connect ("udp://127.0.0.1:5555");

    for (int request_nbr = 0; request_nbr != 10; request_nbr++)
    {
        zmq::message_t request (5);
        memcpy (request.data (), "Hello", 5);
        std::cout << "Sending Hello " << request_nbr << "…" << std::endl;
        socket.send (request);

        sleep(1);
    }

    return 0;
}

服务器为zmq_has()函数输出一个1,这应该验证libzmq是在草稿API模式的基础上构建的。

我需要做些什么才能使RADIO/DISH正常工作?

我想在项目中使用ZMQ作为UDP接收器来接收来自非ZMQ应用程序的一些UDP数据包。

3 个答案:

答案 0 :(得分:2)

RADIO和DISH处于草稿状态,无法在稳定版本中使用。如果您需要访问DRAFT API,请从此link

构建zmq

以下是 zmq.hpp

的一部分
// These functions are DRAFT and disabled in stable releases, and subject to 
// change at ANY time until declared stable.                                 
    #ifdef ZMQ_BUILD_DRAFT_API

    //DRAFT Socket types.                                                       
#define ZMQ_SERVER 12
#define ZMQ_CLIENT 13
#define ZMQ_RADIO 14
#define ZMQ_DISH 15
#define ZMQ_GATHER 16
#define ZMQ_SCATTER 17
#define ZMQ_DGRAM 18
#endif

答案 1 :(得分:0)

休斯顿,我们遇到了一个问题:

我不熟悉条件构建,并且在最近的ZeroMQ版本中包含draft-API。如果确实打算以你假设的方式工作,那么 #define -s应该已经在那里解决了,还没有呢?

也许你已经从GitHub的一些来源中挖掘了#define + ZMQ_RADIO的正确ZMQ_DISH序号,与核心功能兼容,但只是手动的一般方法:

#define                        A_NOT_IMPLEMENTED_CABLE_TV_BROADCAST_ARCHETYPE -1234
void   *dsh = zmq_socket( ctx, A_NOT_IMPLEMENTED_CABLE_TV_BROADCAST_ARCHETYPE );
assert( dsh              && "INF: a socket instantiation from [ctx] failed." );

        rc = bind( dsh, "udp://*:5555" );
assert( rc == 0          && "INF: a socket .bind( 'udp://*.5555' ) failed.");

听起来很可疑,即使有了旗帜ENABLE_DRAFTS=ON的承诺,也不是吗?

摘要

如果您的项目旨在使用RADIO/DISH,请仔细查看已发布的API(有关未实现/未发布功能的警告),您还可以在其中找到其他必需步骤:

  

收音机正在使用群组(与Pub-sub主题相对应),Dish套接字可以加入群组,并且无线电插座发送的每条消息都属于一个群组。

  组是空终止的字符串,限制为16个字符长度(包括null)。目的是将长度增加到40个字符(包括空值)。

  使用完全匹配(与PubSub的前缀匹配)匹配组。

ZMQ_RADIO 方必须使用 zmq_msg_set_group(3) 首先向群组分配消息。

ZMQ_DISH 方必须使用 zmq_join(3) 的电话,以便&#34;输入&#34;一个组以便接收任何消息,因为默认情况下,它实际上没有成员资格。

ZMQ_DISH 方可以使用 zmq_msg_group(3) 来获取邮件实际所属的群组。

ZeroMQ在W.I.P. - 所以可能想检查是否有类似的服务。

如果需要和匆忙,Martin Sustrik已经启动了另一个智能消息/信令工具 -

遇到一些麻烦之后,似乎已经推出了生产版本,其中可扩展的正式沟通模式可以帮助您实现项目目标。 值得一试。

答案 2 :(得分:0)

这里是与这两个一起工作的示例。我已经测试过了。

最重要的事情是您需要检查是否不加载系统zmq库。 就我而言,我在cmake中做了这样的事情:

set(ENABLE_DRAFTS ON)

add_subdirectory(libzmq)
set_target_properties(libzmq PROPERTIES PREFIX "dev-")

# If you want target
add_library(CppZeroMQ INTERFACE)

target_link_libraries(CppZeroMQ INTERFACE $<$<CONFIG:Debug>:libzmq>$<$<CONFIG:Release>:libzmq-static>)
# For CPP headers (you may install and change path here)
target_include_directories(CppZeroMQ INTERFACE my/path/to/cppzmq)
target_compile_definitions(CppZeroMQ INTERFACE ZMQ_BUILD_DRAFT_API=1)

由于它可以从源代码中区分系统lib和您的系统lib。可能系统库未使用DRAFTS。


服务器/发布器部分

    zmq::context_t context(1);
    zmq::socket_t publisher(context, ZMQ_RADIO);
    // We need set IP of destination, sad but true
    publisher.connect("udp://127.0.0.1:30666");

    std::string text;
    text.reserve(128);

    int number = 0;
    while(publisher.connected())
    {
        std::chrono::microseconds timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
            std::chrono::system_clock::now().time_since_epoch());

        text.clear();
        text += std::to_string(timestamp.count());
        text += ";";
        text += std::to_string(++number);

        zmq::message_t update{text.data(), text.size()};
        update.set_group("test");
        std::cout << "Sending: " << timestamp << " number:" << number << std::endl;
        publisher.send(update);
        std::this_thread::sleep_for(1s);
    }

客户/订户部分

    zmq::context_t context(1);
    zmq::socket_t subscriber(context, ZMQ_DISH);
    subscriber.bind("udp://*:30666");
    subscriber.join("test");

    int previousNumber = 0;
    int lostCount = -1;

    while(subscriber.connected())
    {
        zmq::message_t update;

        subscriber.recv(&update);

        std::string_view text(update.data<const char>(), update.size());
        std::cout << text;

        auto splitPoint = text.find(';');
        std::string serverTime = std::string{text.substr(0, splitPoint)};
        std::string serverNumber = std::string{text.substr(splitPoint + 1)};
        auto number = std::stoi(serverNumber);
        if(number != previousNumber + 1)
        {
            ++lostCount;
        }
        previousNumber = number;

        const auto diff =
            system_clock::now() -
            system_clock::time_point{std::chrono::microseconds{std::stoull(serverTime)}};

        // Beautify at: https://github.com/gelldur/common-cpp/blob/master/src/acme/beautify.h
        std::cout << " ping:" << Beautify::nice{diff} << "UDP lost: " << lostCount << std::endl;
    }