ZMQ_CONFLATE在PUB / SUB模式中的行为

时间:2018-12-12 11:03:53

标签: zeromq publish-subscribe

ZeroMQ GitHub issues page开始交叉发布,以提高可见度。

问题描述

注意:这可能是预期的行为。

我正在实现一种PUB / SUB模式,其中有一个发布者(相当快)和多个订阅者(它们具有不同的费率)。

我对最新消息感兴趣。因此,我想启用ZMQ_CONFLATE选项。

我的理解(只是从文档中,我没有检查库的源代码)是仅保留最新消息-大小为1的队列以及最新消息。我们无法使用高水位标记来丢弃新消息。 我假设“用户”代码发送一条消息(zmq_send),zmq_context中的线程池将处理要在套接字上发送的消息。如果在发送旧消息之前出现新消息,则(ZMQ_CONFLATE = true)将丢弃旧消息,然后发送新消息。接收器大小相同。如果用户代码调用zmq_recv的速度很慢,则仅读取最后一条消息。

现在,只要我有1个发布者和1个订阅者,它就可以完美地工作。 如果我添加更多的订户,则只有第一个连接的订户(使用tcp或最后一个(使用ipc)获得消息。 请注意,由发布者方控制行为。在订户中添加ZMQ_CONFLATE无效(在某种意义上,订户可以连接)

所以,我的问题是:这是预期的行为吗? 在发布者侧设置的ZMQ_CONFLATE是否在将消息发送给第一个订户之后丢弃该消息(不是因为已经调用了新的zmq_send)?

环境

我在macOS 13.6,lib zmq(由自制软件安装)4.2.5上对此进行了测试。 我还在两个Debian(4.2.3-1和4.2.1-4)之间进行了测试

我运行的代码如下:

代码

发布者:

#include <zmq.h>

#include <cstdlib>
#include <chrono>
#include <iostream>
#include <thread>
#include <atomic>
#include <csignal>

static std::atomic<bool> s_shutdown(false);

void signal_handler(int) {
    s_shutdown = true;
}

int main(int argc, char** argv)
{
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    void* context = zmq_ctx_new();
    void* output = zmq_socket(context, ZMQ_PUB);


    // We set the internal queue to have only one (the most recent) message and throw away
    // everything else.
    int trueValue = 1;
    zmq_setsockopt(output, ZMQ_CONFLATE, &trueValue, sizeof(int));

    // We are ready. Create the endpoints.
//    zmq_bind(output, "tcp://*:10000");
    zmq_bind(output, "ipc:///tmp/zmq_test");


    unsigned i = 0;
    while(true) {

        if (s_shutdown) {
            break;
        }

        if (zmq_send(output, &i, sizeof(unsigned), 0) ==  -1) {
            std::cerr << "Failed to send message." << std::endl;
        } else {
            std::cerr << "Sending " << i << std::endl;
        }
        i++;

        // fake a sleep (1ms)
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }

    zmq_close(output);
    zmq_ctx_term(context);
    return 0;
}

订户

#include <zmq.h>

#include <cstdlib>
#include <atomic>
#include <csignal>
#include <iostream>
#include <thread>

static std::atomic<bool> s_shutdown(false);

void signal_handler(int) {
    s_shutdown = true;
}

int main(int argc, char** argv)
{
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    void* context = zmq_ctx_new();

    void* input = zmq_socket(context, ZMQ_SUB);

    // subscribe to everything
    zmq_setsockopt(input, ZMQ_SUBSCRIBE, "", 0);
    // Setting the buffer to accept a single message and to drop old messages.
    int trueValue = 1;
     zmq_setsockopt(input, ZMQ_CONFLATE, &trueValue, sizeof(int));

//    zmq_connect(input, "tcp://localhost:10000");
    zmq_connect(input, "ipc:///tmp/zmq_test");

    while(true) {
        // reading the state
        if (s_shutdown) {
            break;
        }

        unsigned readValue = 0;
        int readBytes = zmq_recv(input, &readValue, sizeof(unsigned), ZMQ_DONTWAIT);
        if (readBytes > 0) {
            std::cerr << "Read " << readValue << std::endl;
        }


        // fake a sleep (100ms)
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    zmq_close(input);
    zmq_ctx_term(context);
    return 0;
}

评论发布者中的zmq_setsockopt(output, ZMQ_CONFLATE, &trueValue, sizeof(int));允许多个订阅者接收消息。

0 个答案:

没有答案