【发布时间】:2020-05-20 20:50:32
【问题描述】:
环境:在他们的 Jetson 开发板上使用 NVIDIA 风格的 Ubuntu 18.01 和他们的 TX2i 处理器。 ZMQ 4.3.2,利用 ZMQ 的 cppzmq C++ 包装器。
我有大量使用带有 ZeroMQ 的 google 协议缓冲区运行的代码,而且都是 PUSH/PULL,它工作正常,除了我有一个不是点对点的情况,而是 1: 3.此处正确的解决方案是执行 PUB/SUB,但我无法将消息传递给我的订阅者。
我将代码精简为这个简单的示例。如果我取消注释 #define 语句,订阅者将一无所获。注释(编译为 PUSH/PULL 而不是 PUB/SUB),然后订阅者按预期获得消息。由于sleep_for() 次数过多,我希望订阅者在发布者执行发送之前有足够的时间进行注册。
编辑:
为什么要对订阅者进行尝试/捕获?我很早就遇到了例外,并认为这是因为出版商还没有准备好。这似乎不再是这种情况,所以不是我想的那样。
// Publisher
#include "/usr/local/include/zmq.hpp"
#include "protobuf_namespace.pb.h"
#include <chrono>
#include <thread>
#define PUB_SUB
int main( void )
{
zmq::context_t* m_pContext = new zmq::context_t( 1 );
#ifdef PUB_SUB
zmq::socket_t* m_pSocket = new zmq::socket_t( *m_pContext, ZMQ_PUB );
#else
zmq::socket_t* m_pSocket = new zmq::socket_t( *m_pContext, ZMQ_PUSH );
#endif
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
//m_pSocket->bind( "tcp://*:53001" ); // using '*' or specific IP doesn't change result
m_pSocket->bind( "tcp://127.0.0.1:53001" );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
// Send the parameters
protobuf_namespace::Params params;
params.set_calibrationdata( protobuf_namespace::CalDataType::CAL_REQUESTED ); // init one value to non-zero
std::string params_str = params.SerializeAsString();
zmq::message_t zmsg( params_str.size() );
memcpy( zmsg.data(), params_str.c_str(), params_str.size() );
m_pSocket->send( zmsg, zmq::send_flags::none );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
m_pSocket->close();
zmq_ctx_destroy( m_pContext );
}
// Subscriber - start me first!
#include "/usr/local/include/zmq.hpp"
#include "protobuf_namespace.pb.h"
#include <chrono>
#include <thread>
#include <stdio.h>
#define PUB_SUB
int main( void )
{
zmq::context_t* m_pContext = new zmq::context_t( 1 );
#ifdef PUB_SUB
zmq::socket_t* m_pSocket = new zmq::socket_t( *m_pContext, ZMQ_SUB );
m_pSocket->connect( "tcp://127.0.0.1:53001" );
int linger = 0;
zmq_setsockopt( m_pSocket, ZMQ_LINGER, &linger, sizeof( linger ) );
zmq_setsockopt( m_pSocket, ZMQ_SUBSCRIBE, "", 0 );
#else
zmq::socket_t* m_pSocket = new zmq::socket_t( *m_pContext, ZMQ_PULL );
m_pSocket->connect( "tcp://127.0.0.1:53001" );
#endif
protobuf_namespace::Params params;
zmq::message_t zmsg;
bool retry = true;
do {
try {
m_pSocket->recv( zmsg, zmq::recv_flags::none );
retry = false;
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
} catch( ... ) {
printf("caught\n");
}
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
} while( retry );
std::string param_str( static_cast<char*>( zmsg.data() ), zmsg.size() );
params.ParseFromString( param_str );
if( params.calibrationdata() == protobuf_namespace::CalDataType::CAL_REQUESTED )
printf( "CAL_REQUESTED\n" );
else
printf( "bad data\n" );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
m_pSocket->close();
zmq_ctx_destroy( m_pContext );
}
【问题讨论】:
-
经过更多的实验,我发现如果我绕过 ZMQ 周围的 cppzmq C++ 包装器,并且只在发布者端更改代码,我就可以获取消息。我现在确信 cppzmq 包装器中有一个错误。由于我的项目时间紧迫,我将其用作“公认的解决方案”,直到我有时间进行更深入的研究。
-
更正:SUBSCRIBER端只需要使用C API即可。
标签: c++ protocol-buffers zeromq publish-subscribe