C ++和Python ZeroMQ 4.x PUB / SUB示例不起作用

时间:2017-12-25 20:43:05

标签: python c++ tcp zeromq pyzmq

我只能找到旧的C ++源代码示例。无论如何,我做了我的,基于他们。这是我在python中的发布者:

import zmq
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5563")

while True:
    msg = "hello"
    socket.send_string(msg)
    print("sent "+ msg)
    sleep(5)

这里是C ++中的订阅者:

void * ctx = zmq_ctx_new();
void * subscriber = zmq_socket(ctx, ZMQ_SUB);
// zmq_connect(subscriber, "tcp://*:5563");
   zmq_connect(subscriber, "tcp://localhost:5563");
// zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", sizeof(""));

while (true) {
    zmq_msg_t msg;
    int rc;

    rc = zmq_msg_init( & msg);
    assert(rc == 0);
    std::cout << "waiting for message..." << std::endl;
    rc = zmq_msg_recv( & msg, subscriber, 0);
    assert(rc == 1);

    std::cout << "received: " << (char * ) zmq_msg_data( & msg) << std::endl;
    zmq_msg_close( & msg);
}

最初,我尝试了zmq_setsockopt( subscriber, ZMQ_SUBSCRIBE, "", sizeof("") );,但我想如果我不设置这个,我应该收到所有内容,对吧?所以我对此发表了评论。

当我运行代码时,我看到&#34;等待消息......&#34;永远。

我尝试使用 tcpdump 收听TCP流量。事实证明,当打开发布者时,我会在5563端口看到很多垃圾,当我关闭发布者时,他们会停止。当我尝试PUSH/PULL方案时,我可以在tcpdump中看到明文消息。 (我尝试使用nodejs并使用c ++进行推动并且它有效。)

我可能做错了什么?

我尝试了.bind().connect()localhost127.0.0.1的不同组合,但他们也不会工作。

更新:我刚刚读到我必须订阅某些内容,所以我zmq_setsockopt( subscriber, ZMQ_SUBSCRIBE, NULL, 0 );订阅了所有内容,但我仍然没有收到任何内容

PyZMQ版本为17.0.0.b3,并具有ZeroMQ 4.2.3

C ++有ZeroMQ 4.2.2

更新2:

更新到4.2.3,也不会工作。

4 个答案:

答案 0 :(得分:5)

  

“如果我不设置这个,我想我应该收到所有内容,对吧?

不,这不是一个正确的假设。您可能想要collection of my other ZeroMQ posts here, about a { plain-string | unicode | serialisation }-issues and the { performance- | traffic- }-impacts actual policy ( SUB-side topic-filter processing on early ZeroMQ versions, and/or the PUB-side processing for more recent ones ) one may encounter in heterogeneous distributed-systems' design, using ZeroMQ.

(任何其他可伸缩形式通信原型模式,与观察到的PUSH/PULL一样,对订阅策略不起作用,因此将独立于针对设置的主题过滤器列表的订阅匹配处理。)

步骤0:首先测试发送部分RTO,如果.send() - 是否有任何内容:

让我们模拟一个快速的pythonic接收器,看看,如果发送者确实发送了任何东西:

import zmq

aContext = zmq.Context()                                          # .new Context
aSUB     = aContext.socket( zmq.SUB )                             # .new Socket
aSUB.connect( "tcp://127.0.0.1:5563" )                            # .connect
aSUB.setsockopt( zmq.LINGER, 0 )                                  # .set ALWAYS!
aSUB.setsockopt( zmq.SUBSCRIBE, "" )                              # .set T-filter

MASK = "INF: .recv()-ed this:[{0:}]\n:     waited {1: > 7d} [us]"
aClk = zmq.Stopwatch(); 

while True:
      try:
           aClk.start(); print MASK.format( aSUB.recv(),
                                            aClk.stop()
                                            )
      except ( KeyboardInterrupt, SystemExit ):
           pass
           break
pass
aSUB.close()                                                     # .close ALWAYS!
aContext.term()                                                  # .term  ALWAYS!

这应该报告 PUB -sender实际上是.send() - 通过电汇以及实际消息到达间隔时间([us]很高兴ZeroMQ已将此工具用于调试和性能/延迟调整。)

如果您看到实时 INF: 消息确实在屏幕上显示确认,请继续运行,现在可以继续执行下一步。

步骤1:接下来测试接收部分代码:

#include <zmq.h>
void *aContext = zmq_ctx_new();        
void *aSUB     = zmq_socket(     aContext, ZMQ_SUB );               std::cout << "INF: .. zmq_ctx_new() done" << std::endl;
                 zmq_connect(    aSUB,    "tcp://127.0.0.1:5563" ); std::cout << "INF: .. zmq_connect() done" << std::endl;
                 zmq_setsockopt( aSUB,     ZMQ_SUBSCRIBE, "", 0 );  std::cout << "INF: .. zmq_setsockopt( ZMQ_SUBSCRIBE, ... ) done" << std::endl;
                 zmq_setsockopt( aSUB,     ZMQ_LINGER,        0 );  std::cout << "INF: .. zmq_setsockopt( ZMQ_LINGER, ...    ) done" << std::endl;
int rc;
while (true) {
         zmq_msg_t       msg;                            /*       Create an empty ØMQ message */
    rc = zmq_msg_init  (&msg);          assert (rc ==  0 && "EXC: in zmq_msg_init() call" );
                                               std::cout << "INF: .. zmq_msg_init() done" << std::endl;
    rc = zmq_msg_recv  (&msg, aSUB, 0); assert (rc != -1 && "EXC: in zmq_msg_recv() call" );
                                               std::cout << "INF: .. zmq_msg_recv() done: received [" << (char * ) zmq_msg_data( &msg ) << "]" << std::endl;
         zmq_msg_close (&msg);                           /*       Release message */
                                               std::cout << "INF: .. zmq_msg_close()'d" << std::endl;
}
zmq_close(    aSUB );                          std::cout << "INF: .. aSUB was zmq_close()'d" << std::endl;
zmq_ctx_term( aContext );                      std::cout << "INF: .. aCTX was zmq_ctx_term()'d" << std::endl;

答案 1 :(得分:2)

zmq_setsockopt() 的返回值是多少?

然后你应该使用 "" 而不是 NULL ,它们是不同的。

zmq_setsockopt( subscriber, ZMQ_SUBSCRIBE, "", 0 );

API定义:

  

返回值

     

如果成功,zmq_setsockopt()函数将返回零。否则,它将返回-1并将 errno 设置为以下定义的值之一。
  ...

答案 2 :(得分:2)

运行PUB / SUB模式(不论语言)的正确配方是:

公布

  1. socket(zmq.PUB)
  2. bind("tcp://127.0.0.1:5555")
  3. 编码(对于字符串通常只是encode(),但你也可以对对象进行压缩()或转储(),甚至两者都有。encoded_topic = topic.encode() encoded_msg = msg.encode()
  4. send_multipart([encoded_topic, encoded_msg])
    1. socket(zmq.SUB)
    2. setsockopt(zmq.SUBSCRIBE, topic.encode())
    3. connect("tcp://127.0.0.1:5555")
    4. answer = recv_multipart()
    5. 解码答案enc_topic, enc_msg = answer topic = enc_topic.decode() msg = enc_msg.decode()
    6. 一般来说,步骤Pub - 2 / Sub - 3(即绑定/连接)和Pub - 3 / Sub -  5(即编码/解码或转储/加载)需要相互补充才能使事情发挥作用。

答案 3 :(得分:0)

是我,是问这个问题的人。

我设法通过 中交换 socket.bind("tcp://*:5563")socket.connect("tcp://dns_address_of_my_dcker_container:5564") 来工作

并在C ++中将zmq_connect(subscriber, "tcp://localhost:5563")zmq_bind(subscriber, "tcp://*:5563") 交换

我在网上找到的示例说我应该为发布商使用bind,为订阅者使用connect,但这对我来说不会有任何作用。有谁知道为什么?

ZeroMQ文档说明如下:

  

zmq_bind()函数将套接字绑定到本地端点,然后   接受该端点上的传入连接。

     

zmq_connect()函数将套接字连接到端点,然后   接受该端点上的传入连接。

我不知道发生了什么变化,但它确实有效。