如何将数据序列化为C++ zmq 客户端和 Python zmq 服务器之间的通信

How to can I serialize data to Communication between C++ zmq client and Python zmq Server

本文关键字:zmq Python 服务器 之间 通信 客户端 数据 序列化 C++      更新时间:2023-10-16

>更新我的问题

如何在我的python zmq服务器中表示到达的消息以显示其内容?

根据这种行为,我可以假设btnState数据无论如何都会发送到python服务器吗?

上下文:

我正在发送一些数据成员结构 使用 C++ ZeroMQ 客户端进程:ZMQComponent.h文件

#include <zmq.hpp>
#include <sofa/defaulttype/VecTypes.h>
// To Quat datatype
#include <sofa/defaulttype/Quat.h>
using sofa::defaulttype::Quat;
using std::string;
namespace sofa
{
namespace component
{
namespace controller
{
/* data structure which I want send data to python zmq server */
struct instrumentData
{
typedef sofa::defaulttype::Vec3d Vec3d;
Vec3d pos;
Quat quat;
int btnState;
float openInst;
bool blnDataReady;
};
class ZMQComponent : public sofa::core::behavior::BaseController
{
public:
SOFA_CLASS(ZMQComponent, sofa::core::behavior::BaseController);
ZMQComponent();
virtual ~ZMQComponent();
/* Conect to ZMQ external python Server  */
void setupConnection();
/* Send some data memeber instrumentData structure to ZMQ external Server  */
void instrumentDataSend(instrumentData a);
/* initialize function */
void init();
};
} // namespace sofa
} // namespace component
} // namespace controller

ZMQComponent.cpp是:

#include <sofa/core/ObjectFactory.h>
#include <zmq.hpp>
#include <iostream>
#include <string>
#include "ZMQComponent.h"

using namespace std;
namespace sofa
{
namespace component
{
namespace controller
{
/*  ZMQ Internal Client context and socket */
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
ZMQComponent::ZMQComponent(){}
void ZMQComponent::setupConnection()
{
cout << "Connecting to python zeroMQ server ..." << endl;
socket.connect("tcp://localhost:5555");
}
void ZMQComponent::instrumentDataSend(instrumentData a)
{
/*  Initialize the data members structure instrumentData */
a.pos = sofa::defaulttype::Vec3d(1.0f, 1.0f, 1.0f);
a.quat = defaulttype::Quat(1.0f, 1.0f, 4.0f, 1.0f);
a.btnState = 5671;
a.openInst = 1.0f;
a.blnDataReady = false;
string s, test, result, d;
s = to_string(a.btnState);
test = " is a number";
result = s + test;
/*  We send  the btnState data  */
zmq::message_t request(30);

/*  We ask for the memory address to ge the btnState content and send it. */
memcpy(request.data(), &result, 30);
socket.send(request);
}

/*  In the init function we create the objects to setup connection and send data  */
void ZMQComponent::init()
{
std::cout << "ZeroMQCommunication::init()" << std::endl;
ZMQComponent z;
z.setupConnection();
instrumentData itemp;
z.instrumentDataSend(itemp);
}
/*  Other code related ....  */
ZMQComponent::~ZMQComponent(){}
// int ZeroMqComponentClass = sofa::core::RegisterObject("This component does nothing.").add<ZeroMqComponent>();
SOFA_DECL_CLASS(ZMQServerComponent)
int ZMQServerComponentClass = sofa::core::RegisterObject("This component create a Socket.").add< ZMQServerComponent >();
} // namespace controller
} // namespace component
} // namespace sofa

然后,我的python zmq服务器接收btnStateint变量是:

import time
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")
print('ZMQ Server listening ... ')
while True:
#  Wait for next request from client
message = socket.recv()
print("Received message from Sofa: {}".format(message))
#  Do some 'work'
time.sleep(1)

到达python zmq服务器的输出或消息是result变量的内容(btnState在s内容变量中变成字符串+字符串test连接)和一些符号字符:

(cnvss_test) ➜  Python git:(ZMQCommunication) ✗ python server.py
ZMQ Server listening ...
Received message from Sofa: b'xb0x1dx19xf4xfdx7fx00x00x0ex00x00x00x00x00x00x0045 is a number'

我的 ZMQ python 服务器脚本上的先前输出显示,从沙发result的字符串已到达服务器,并且它们的内容已可视化,但这些字符串或字符符号也是我的 C++ 客户端中定义的zmq::message_t request(30)大小的产物或结果。

如果我在请求中分配小于 30 的值,例如zmq::message_t request(10)服务器中的输出为:

Received message from Sofa: b'x90x94xa1x00xfcx7fx00x00x0ex00'

如果我在请求中分配一个大于 10 的值,例如zmq::message_t request(20)我的服务器中的输出是:

Received message from Sofa: b'x80$(xc7xfcx7fx00x00x0ex00x00x00x00x00x00x0045 i

然后,我在服务器端收到的字符串或对象,它的长度或大小与分配给变量zmq::message_t request一样长

基于上面提到的,ZMQ 是谁在我收到的消息中添加此字符串的?

根据前面的过程,我的消息到达我的服务器,那么正确的尝试是需要什么带有协议缓冲区之类的实体的序列化过程? 我知道使用像谷歌协议缓冲区这样的东西允许在发送的对象和接收的对象相对于其真实内容方面进行更严格的控制......

无论如何,如何删除到达服务器的消息中添加的字符串或字符符号?

任何支持或方向将不胜感激

您的系统是异构的,这意味着您需要某种与平台/语言无关的序列化。

就您的目的而言,最方便使用的一种可能是Google Protocol Buffers.这很好地支持了C++和Python。有了这个,您将在模式文件中定义消息/数据结构(文件扩展名.proto),并使用protoc将其编译为C++源代码和Python源代码。这些类可以序列化/反序列化为同一连线格式/从同一连线格式反序列化。序列化/反序列化可以很好地与 ZMQ 消息缓冲区集成。

还有其他的;

  • Apache Avro是可能的。
  • 我会避免XSD模式;原则上它们很好,但找到真正完成正确和完整工作的代码生成器是困难/昂贵的。例如,xsd.exe(来自Microsoft)可以编译 XSD 架构以C++类(我认为),但忽略架构中的约束字段(例如。MinInclusive)。
  • ASN1真的很好,但我还没有找到一个像样的Python实现。有一个用于python(pyasn)的ASN.1的代码优先实现,但这忽略了拥有ASN.1模式的全部意义......

我在 c++ 中使用了类似的 zmq 实现和沙发框架(与 autor 插件相关)。

将数据从 zmq C++发送到 python zmq 没有任何问题。

以下是我用python编写的zmq服务器的概述:

import zmq
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.setsockopt(zmq.SUBSCRIBE, "")
print "Collecting data from c++ ..."
socket.connect ("tcp://127.0.0.1:6000")
while True:
print socket.recv()

以下是结果的概述:

douaille@douaille:~/Documents/zmq$ python zmqClient.py 
Collecting data from c++ ...
/colorLight string:'1 1 1 1' 
/colorLight string:'1 1 1 1' 
/colorLight string:'1 1 1 1' 
/colorLight string:'1 1 1 1' 
/colorLight string:'1 1 1 1' 
/colorLight string:'1 1 1 1' 

我正在使用 zmq 作为发布者,但它不会根据您的需求更改任何内容。另外,请求客户端的实现几乎相同。 看起来您正在打印请求而不是消息

你可以在这里找到 c++ 发送器部分的实现: https://github.com/SofaDefrost/sofa/blob/sofaCommunication/applications/plugins/Communication/components/serverCommunicationZMQ.inl

编辑:

下面是一个使用 zmq 请求的示例:

import zmq
context = zmq.Context()
socket = context.socket(zmq.REQ)
print("Collecting data from c++ using REQ ...")
socket.connect("tcp://localhost:6000")
while True:
print("Sending request")
socket.send(b"Hello")
message = socket.recv()
print("Received reply : %s" % message)

结果:

douaille@douaille:~/Documents/zmq$ python zmqClient.py 
Collecting data from c++ using REQ ...
Sending request
Received reply : /colorLight string:'1 1 1 1' 
Sending request
Received reply : /colorLight string:'1 1 1 1' 
Sending request
Received reply : /colorLight string:'1 1 1 1'