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

时间:2018-01-25 05:14:52

标签: python c++ serialization zeromq

更新我的问题

如何在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

然后,接收btnState int变量的python zmq服务器是:

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'\xb0\x1d\x19\xf4\xfd\x7f\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x0045 is a number'

我的ZMQ python服务器脚本上的上一个输出显示沙发中的字符串result已到达服务器,其内容可视化,但这些字符串或字符符号也是产品或结果开头我在C ++客户端中定义的zmq::message_t request(30)的大小。

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

Received message from Sofa: b'\x90\x94\xa1\x00\xfc\x7f\x00\x00\x0e\x00'

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

Received message from Sofa: b'\x80$(\xc7\xfc\x7f\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x0045 i

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

基于上面提到的,是ZMQ在收到的消息中添加了这个字符串吗?

根据前面的过程,我的消息到达我的服务器,然后是正确的尝试什么序列化过程与一些实体如协议缓冲区是必要的? 据我所知,使用谷歌协议缓冲区之类的东西可以让一些相关性更加受控,与发送的对象和收到的与其真实内容相关的对象...

在任何情况下,如何删除邮件中添加的字符串或字符符号到达服务器?

任何支持或指导都将受到高度赞赏

2 个答案:

答案 0 :(得分:1)

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

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

还有其他人;

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

答案 1 :(得分: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 ++ sender部分的实现: 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'