ZeroMQ PUSH / PULL

时间:2014-08-08 02:30:14

标签: c++ zeromq publish-subscribe

zmq的某些部分没有以可预测的方式表现。

我使用VS2013和zmq 3.2.4。为了不失去'我的pubsub框架中的消息[旁白:我认为这是一个设计缺陷。我应该能够先启动我的订阅者,然后发布者和我应该收到所有消息]我必须将发布者与订阅者la durapub/durasub等同步。我正在使用durasub.cpp和durapub.cpp中的示例zeromq指南。 如果我按原样使用示例,则系统可以正常运行。

如果我现在在durasub.cpp

中的ZMQ_PUSH附近添加范围括号
{
    zmq::socket_t sync (context, ZMQ_PUSH);
    sync.connect(syncstr.c_str());
    s_send (sync, "sync");
}

系统停止工作。匹配' ZMQ_PULL'信号永远不会达到durapub.cpp中的应用程序级别。

我已经通过C ++包装器来检查来自zmq_close的返回值,一切都很顺利。就ZMQ而言,它已将消息传递给端点。 希望我做过一些明显愚蠢的事情?

还有更多。

的加入
std::this_thread::sleep_for(std::chrono::milliseconds(1));

允许系统(即pub / sub)重新开始工作。所以它显然是一种竞争条件,大概是在收割者的线程中,因为它破坏了套接字。

更多的挖掘。我认为LIBZMQ-179也提到了这个问题。


编辑#2 2014-08-13 03:00 [UTC + 0000]

Publisher.cpp:

#include <zmq.hpp>
#include <zhelpers.hpp>
#include <string>
int main (int argc, char *argv[]) 
{
    zmq::context_t context(1);
    std::string bind_point("tcp://*:5555"); 
    std::string sync_bind("tcp://*:5554"); 
    zmq::socket_t sync(context, ZMQ_PULL);
    sync.bind(sync_bind.c_str());

    //  We send updates via this socket
    zmq::socket_t publisher(context, ZMQ_PUB);
    publisher.bind(bind_point.c_str());

    //  Wait for synchronization request
    std::string tmp = s_recv (sync);        
    std::cout << "Recieved: " << tmp << std::endl;          

    int numbytessent = s_send (publisher, "END");       
    std::cout << numbytessent << "bytes sent" << std::endl;
 }

Subscriber.cpp

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

int main (int argc, char *argv[])
{   
    std::string connectstr("tcp://127.0.0.1:5555"); 
    std::string syncstr("tcp://127.0.0.1:5554");    

    zmq::context_t context(1);

    zmq::socket_t subscriber (context, ZMQ_SUB);
    subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    subscriber.connect(connectstr.c_str());

#if ENABLE_PROBLEM
    {
#endif ENABLE_PROBLEM
        zmq::socket_t sync (context, ZMQ_PUSH);
        sync.connect(syncstr.c_str());
        s_send (sync, "sync");
#if ENABLE_PROBLEM
    }
#endif ENABLE_PROBLEM

    while (1) 
    {
        std::cout << "Receiving..." << std::endl;
        std::string s = s_recv (subscriber);
        std::cout << s << std::endl; 
        if (s == "END")
        {
            break;
        }
    }  
}
  1. 将每个cpp编译为自己的exe。
  2. 启动两个exes(起始顺序无关紧要)
  3. 如果定义ENABLE_PROBLEM

    • 发布者:( EMPTY提示)
    • 订阅者:&#39;正在接收...&#39; 然后你必须杀死这两个进程,因为它们已经挂起......

    如果未定义ENABLE_PROBLEM

    • 发布者:&#39;收到:同步&#39; &#39;发送3个字节&#39;
    • 订阅者:&#39;正在接收...&#39; &#39; END&#39;

1 个答案:

答案 0 :(得分:1)

编辑#1 2014-08-11:原始帖子已更改,未显示修订版

目标是什么?

在充分尊重的情况下,很难分离目标并模拟任何通过/失败测试来验证目标,而不仅仅是上面的三个SLOC。

让我们一步一步地开始。

那里使用了什么ZMQ原语?

T.B.D。

编辑后#1 ZMQ_PUSH + ZMQ_PULL +(隐藏 {{1 <}> + ZMQ_PUB ...下次发布的是ProblemDOMAIN上下文完整的来源,最好的是自我测试用例输出:

ZMQ_SUB

部署了什么ZMQ-context创建/终止生命周期策略?

T.B.D。

post-EDIT#1 :n.b:ZMQ_LINGER会影响资源的 ... // <code>-debug-isolation-framing ------------------------------------------------ std::cout << "---[Pre-test]: sync.connect(syncstr.c_str()) argument" << std::endl; std::cout << syncstr.c_str() << std::endl; std::cout << "---[Use/exec]: " << std::endl; sync.connect( syncstr.c_str()); // <code>-debug-isolation-framing ------------------------------------------------ ... ,这可能会在ZMQ_Context终止出现之前占用。 (并且可以阻止......伤害......)

关于“ZMQ_LINGER何时真正重要?”的说明

此参数在.close()即将终止时生效,而发送队列尚未清空并且正在尝试Context处理。

在大多数架构中......(低延迟/高性能,微秒和纳秒计数......),(共享/受限)资源设置/处置操作出现的原因很多 < / strong>在系统生命周期结束时的最开始,。不用说更多原因,只需想象一下与所有设置/丢弃操作直接相关的开销,这些开销完全不可能发生(重复发生的次数越少......)在近乎真实的日常操作流程中时间系统设计。

因此,让系统进程进入最后的“整理”阶段(就在退出之前)

设置zmq_close()只会忽略&lt; 发件人&gt; 队列中的任何内容,并允许提示ZMQ_LINGER == 0 + {{ 1}}

同样地,zmq_close()会将&lt; 发件人&gt; 的队列中的任何内容置于 [拥有最大价值] ,整个系统必须等待ad-infimum ,之后(希望是任何)&lt; receiver &gt; 检索&amp;在允许任何zmq_term() + ZMQ_LINGER == -1被允许发生之前,“消耗”所有已排队的消息......这可能会很长并完全超出您的控制范围......

最后zmq_close()作为妥协来等待一定数量的[msec] -s,如果某些&lt; 接收器&gt; 来了并检索一个已列出的消息。但是,在给定的TimeDOMAIN里程碑中,系统会前进到zmq_term() + ZMQ_LINGER > 0以正常清理所有保留资源,并根据系统设计时序约束退出。