追问:升压序列化定制的C ++对象越过ZeroMQ拉插座 [英] Follow up: Boost serialized custom C++ object passed over ZeroMQ pull socket

查看:155
本文介绍了追问:升压序列化定制的C ++对象越过ZeroMQ拉插座的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我打开了早些时候在另一个线程在<一个跟进的问题href=\"http://stackoverflow.com/questions/14565538/boost-de-serializing-a-custom-c-object-passed-over-zeromq-pull-socket\">Boost:反序列化的自定义C ++对象越过ZeroMQ拉插座。在该线程的问题已根据所提供的回答得到解决。现在,我已经在运行时的另一个问题。请参阅下面的说明。我realtively新的C ++的境界,所以我AP preciate如果你告诉我在除了提供给我下的问题说明书descibed的code的任何部分,任何改善的必要。

说明:

我有一个C ++类名为 GenericMessage 它只是持有ID和数据作为其成员(见下文code段2 - GenericMessage.hxx)。我的目的是序列化这个类的一个实例,并通过它实现了推模式的ZeroMQ套接字发送。

序列化和发送任务已在实施的类ZMQHandler (见sendToBE功能),它放置在 code片段3 <显示一个头文件名ZMQHandler.hxx / STRONG>下面。这个类是通过实例化 TestFE.cxx 中显示的的4RD code段之下。

在GenericMessage实例的接收和反序列化的实施 TestBE.cxx 5 code段可用下面。我的目的是在ZMQ插座(即拔插座),反序列化,然后将其成员打印到标准输出接收GenericMessage实例。

我核实,seriazalition和传输在ZeroMQ套接字正常工作的GenericMessage对象。反序列化似乎因为我没有得到任何异常或分段故障类似的事情正常工作。

问题陈述:

什么是从code在TestBE.cxx预期(见code段5)是接收GenericMessage对象在ZeroMQ套接字反序列化,然后打印它的两个成员,即ID和数据是在这种情况下字符串对象。更多precisely应该先打印它获得的字符流,然后反序列化对象的成员的内容。相反,它不会在所有打印这些成员。铝,它把怪异的符号,包括问号到接收字符流。请参阅下面的第一个code片段中,你会看到我的意思。

问题:

我)为什么我不能得到预期的输出?为什么我看到的问题标志着输出奇怪的符号?为什么我没有看到打印的ID和数据字段虽然他们是印刷字符流可见?

二)在GenericMessage类中的数据字段是用于测试目的被设置到std模板类型::字符串。然而,在实际使用中,我计划在一个序列化的形式传送更复杂的对象。在这方面,你认为使用类的boost ::存档:: text_iarchive和boost ::档案:: text_oarchive的是非常有用的。我应该使用二进制呢?如果是这样,有没有你觉得我应该知道的一些缺陷/可能出现的问题?先谢谢了。

SNIPPET 1:程序输出与预期输出

  *******************
  预期输出
  *******************
  连接到FE ...
  CHAR [22 ::系列化存档9 0 1 0
  0 1 12你好!]
  ID:1
  数据:你好!  CHAR [22 ::系列化存档9 0 1 0
  0 2 12你好!]
  ID:2
  数据:你好!  CHAR [22 ::系列化存档9 0 1 0
  0 3 12你好!]
  ID:3
  数据:你好!  ......
  *************************
  打印输出在现实中
  *************************
  连接到FE ...
  CHAR [22 ::系列化存档9 0 1 0
  0 1 12你好!]
  ID:1
  数据:你好!  //继续在以下作为上述递增的顺序相同,直到18消息
  CHAR [22 ::系列化存档9 0 1 0
  0 18 12你好!]
  ID:0
  数据:  // !!!! 18日消息,我打印的字符流中得到了问号后!!!!!
  CHAR [22 ::系列化存档9 0 1 0
  0 19 12你好!]
  ID:0
  数据:  CHAR [22 ::系列化存档9 0 1 0
  0 20 12你好!]
  ID:0
  数据:

code SNIPPET 2(GenericMessage.hxx)

 的#include&LT;&iostream的GT;
  #包括LT&;串GT;
  #包括LT&;&sstream GT;
  #包括LT&;升压/系列化/ serialization.hpp&GT;
  #包括LT&;升压/存档/ binary_oarchive.hpp&GT;
  #包括LT&;升压/存档/ binary_iarchive.hpp&GT;
  #包括LT&;升压/存档/ text_oarchive.hpp&GT;
  #包括LT&;升压/存档/ text_iarchive.hpp&GT;  模板&LT;类T&GT;
  类GenericMessage {
  上市:
    GenericMessage():
      beId(-1)
    {}    GenericMessage(INT ID,T MSG):
       beId(ID),
       数据(MSG)
    {}    〜GenericMessage(){}    ŧ的getData()
    {
      返回的数据;
    }
    标准::字符串的toString()
    {
       的std :: ostringstream SS;
       SS&LT;&LT; getBeId();
       标准::字符串RET = ss.str();      返回(ID:+保留+DATA:+的getData());
    }    无效setBeId(INT ID)
    {
      beId = ID;
    }    INT getBeId()
    {
      返回beId;
    }
  私人的:
    友元类的boost ::系列化::访问;    INT beId;
    数据T;
    模板&LT;类归档和GT;
    无效连载(归档和放大器; AR,const的无符号整型版)
    {
        AR&安培; beId;
        AR&安培;数据;
    }   };

code SNIPPET 3(ZmqHandler.hxx)

 的#includezmq.hpp
   #包括GenericMessage.hxx
   #包括LT&;&unistd.h中GT;
   #包括LT&;&了cassert GT;   模板&LT;类A&GT;
   类ZmqHandler {
      上市:         ZmqHandler():
     mContext(1),
     mOutbHandlerSocket(mContext,ZMQ_PUSH)
         {
             mOutbHandlerSocket.bind(TCP:// *:5555);
         }
         〜ZmqHandler(){}         无效sendToBE(GenericMessage&LT; A&GT; * theMsg)
         {
            的std :: ostringstream archive_stream;
            提高::档案:: text_oarchive的存档(archive_stream);            尝试
            {
                归档&LT;&LT; theMsg;
            }赶上(升压::档案:: archive_exception&安培;除息){
                性病::法院LT&;&LT; 反序列化过程中存档例外:&LT;&LT;的std :: ENDL;
                性病::法院LT&;&LT; ex.what()&所述;&下;的std :: ENDL;
            }赶上(INT E){
                性病::法院LT&;&LT; EXCEPTION&LT;&LT; E&LT;&LT;的std :: ENDL;
            }           标准::字符串outbound_data_ = archive_stream.str();
           //没有必要使用C风格的字符串函数'strlen的
           INT LEN = outbound_data_.length();           ZMQ :: message_t msgToSend(LEN);
           的memcpy(msgToSend.data(),outbound_data_.data(),LEN);           mOutbHandlerSocket.send(msgToSend);
           性病::法院LT&;&LT; 发送的请求:&LT;&LT; theMsg-&GT;的toString()&LT;&LT; ]&LT;&LT;的std :: ENDL;
           性病::法院LT&;&LT; 长度[&LT;&LT; LEN&LT;&LT; ]&LT;&LT;的std :: ENDL;
         }        私人的:
          ZMQ :: context_t mContext;
          ZMQ :: socket_t mOutbHandlerSocket;
     };

code SNIPPET 4(TestFE.cxx)

 的#includeZmqHandler.hxx       诠释的main()
       {
            ZmqHandler&LT;标准::字符串&GT; zmqHandler;
            INT计数器= 1;            而(1)
            {
                性病::字符串数据=你好!;
                GenericMessage&LT;标准::字符串&GT;味精(计数器,数据);
                zmqHandler.sendToBE(安培;味精);
                反++;
                睡眠(1);
             }             返回0;
        }

code SNIPPET 5(TestBE.cxx)

 的#includezmq.hpp
       #包括GenericMessage.hxx
       #包括LT&;&的fstream GT;       诠释的main()
       {
          // prepare我们的背景和插座
          ZMQ :: context_t上下文(1);
          ZMQ :: socket_t插座(背景下,ZMQ_PULL);         性病::法院LT&;&LT; 连接到FE ......&LT;&LT;的std :: ENDL;
         socket.connect(TCP://本地主机:5555);         而(1){
              ZMQ :: message_t回复;
              socket.recv(安培;回复);              为const char * BUF =的static_cast&LT;为const char *&GT;(reply.data());
              性病::法院LT&;&LT; CHAR [&LT;&LT; BUF&LT;&LT; ]&LT;&LT;的std :: ENDL;              标准::字符串input_data_(BUF,reply.size());
              的std :: istringstream archive_stream(input_data_);
              提高::档案:: text_iarchive存档(archive_stream);
              GenericMessage&LT;标准::字符串&GT; theMsg;              尝试
              {
                 归档&GT;&GT; theMsg;
              }赶上(升压::档案:: archive_exception&安培;除息){
                 性病::法院LT&;&LT; 反序列化过程中存档例外:&LT;&LT;的std :: ENDL;
                 性病::法院LT&;&LT; ex.what()&所述;&下;的std :: ENDL;
              }赶上(INT E){
                 性病::法院LT&;&LT; EXCEPTION&LT;&LT; E&LT;&LT;的std :: ENDL;
              }              性病::法院LT&;&LT; ID:&LT;&LT; theMsg.getBeId()&所述;&下;的std :: ENDL;
              性病::法院LT&;&LT; 数据:&LT;&LT; theMsg.getData()&所述;&下;的std :: ENDL;           }            返回0;
         }


解决方案

当我建立我的系统上运行您的code, TestBE 并抛出反序列化异常(每次)。这是我做修复它:

在你的 ZmqHandler 类,改变方法无效sendToBE(GenericMessage&LT; A&GT; * theMsg)无效sendToBE(GenericMessage&LT; A&GT; theMsg)。您可以使用常量和放大器; 如果你想,但你可能不希望在这里使用的指针。在同样的方法,需要修改 theMsg-&GT; XXX theMsg.XXX ,因为 theMsg 不再是一个指针。

TestFE zmqHandler.sendToBE(安培;味精); 变成 zmqHandler。 sendToBE(MSG);

如果 theMsg 必须是一个指针

ZmqHandler ,只需更改行归档和LT;&LT; theMsg 归档和LT;&LT; * theMsg 。这样一来,归档的运营商的LT;&LT; 正在与对象,而不是一个指向对象。您code的其余部分可以保持不变。

This is a follow up problem that I opened up earlier in another thread at Boost: De-serializing a custom C++ object passed over ZeroMQ pull socket. The problem in that thread has been resolved based on the answer provided. Now I have another problem at runtime. Please, see the below description. I am realtively new to C++ realm so I appreciate if you tell me any necessity for improvement in any part of the code provided in addition to what I descibed under problem statment.

Description:

I have a C++ class named GenericMessage which simply holds an id and data as its members (See code snippet 2 below - GenericMessage.hxx). My intention is to serialize an instance of this class and send it via a ZeroMQ socket which implements the push pattern.

The serialization and sending task has been implemented in class ZMQHandler (see sendToBE function) which is placed in a header file name ZMQHandler.hxx shown in the code snippet 3 below. This class is instantiated by TestFE.cxx shown in the 4rd code snippet below.

The receiving and de-serialization of the GenericMessage instance is implemented in TestBE.cxx available in the 5th code snippet below. My intention is to receive the GenericMessage instance over the ZMQ socket (i.e. pull socket), de-serialize it and then print its members to standard output.

I verified that seriazalition and the GenericMessage object that is transferred over the ZeroMQ socket works fine. Deserialization seems to work as well cause I dont get any exception or segmentation fault like thing.

Problem Statement:

What is expected from the code in TestBE.cxx (see code snippet 5) is to receive the GenericMessage object over the ZeroMQ socket deserialize it and then print its two members namely id and data which is a string object in this case. More precisely it should first print the content of the char stream it gets and then the members of the de-serialized object. Instead, it does not print these members at all. Al, it puts weird symbols including question marks into the received char stream. Please see the 1st code snippet below, you'll see my point.

QUESTIONs:

i) Why cannot I get the expected output? Why do I see the question marked weird symbols in the output? Why I don't see the id and data fields printed although they are visible in the printed char stream?

ii) The data field in the GenericMessage class is a template type which is set to std::string for testing purposes. However, in real use, I plan to transfer a much more complex object in a serialized form. In this respect, do you think the use of classes boost::archive::text_iarchive and boost::archive::text_oarchive is useful. Should I use binary instead? If so, is there some pitfalls/possible problems that you think I should be aware of? Thanks in advance.

SNIPPET 1: Program output vs. expected output

  *******************
  The EXPECTED OUTPUT
  *******************
  Connecting to FE...
  CHAR [22 serialization::archive 9 0 1 0
  0 1 12 Hello there!]
  ID: 1
  Data: Hello there!

  CHAR [22 serialization::archive 9 0 1 0
  0 2 12 Hello there!]
  ID: 2
  Data: Hello there!

  CHAR [22 serialization::archive 9 0 1 0
  0 3 12 Hello there!]
  ID: 3
  Data: Hello there!

  ......


  *************************
  PRINTED OUTPUT IN REALITY
  *************************
  Connecting to FE...
  CHAR [22 serialization::archive 9 0 1 0
  0 1 12 Hello there!]
  ID: 1
  Data: Hello there!

  //continues in increasing order same as above until the 18th message in the following
  CHAR [22 serialization::archive 9 0 1 0
  0 18 12 Hello there!]
  ID: 0
  Data: 

  //!!!!AFTER the 18th message I got question marks in the printed char stream!!!!!
  CHAR [22 serialization::archive 9 0 1 0
  0 19 12 Hello there!���]
  ID: 0
  Data: 

  CHAR [22 serialization::archive 9 0 1 0
  0 20 12 Hello there!���]
  ID: 0
  Data: 

CODE SNIPPET 2 (GenericMessage.hxx)

  #include <iostream>
  #include <string>
  #include <sstream>
  #include <boost/serialization/serialization.hpp>
  #include <boost/archive/binary_oarchive.hpp>
  #include <boost/archive/binary_iarchive.hpp>
  #include <boost/archive/text_oarchive.hpp>
  #include <boost/archive/text_iarchive.hpp>

  template <class T>
  class GenericMessage {
  public:
    GenericMessage(): 
      beId(-1)
    {}

    GenericMessage(int id, T msg): 
       beId(id), 
       data(msg)
    {}

    ~GenericMessage(){}

    T getData()
    {
      return data;
    }


    std::string toString()
    {
       std::ostringstream ss;
       ss << getBeId();
       std::string ret =  ss.str();

      return ("ID: " + ret + " DATA: " + getData());
    }

    void setBeId(int id)
    {
      beId = id;
    }

    int getBeId()
    {
      return beId;
    }


  private:
    friend class boost::serialization::access;

    int beId;
    T data;


    template <class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & beId;
        ar & data;
    }

   };

CODE SNIPPET 3 (ZmqHandler.hxx)

   #include "zmq.hpp"
   #include "GenericMessage.hxx"
   #include <unistd.h>
   #include <cassert>

   template <class A>
   class ZmqHandler {
      public:

         ZmqHandler():
     mContext(1),
     mOutbHandlerSocket(mContext, ZMQ_PUSH)
         {    
             mOutbHandlerSocket.bind ("tcp://*:5555");       
         }


         ~ZmqHandler() {}

         void sendToBE(GenericMessage<A> *theMsg)
         {
            std::ostringstream archive_stream;
            boost::archive::text_oarchive archive(archive_stream);

            try
            {
                archive << theMsg;
            } catch (boost::archive::archive_exception& ex) {
                std::cout << "Archive Exception during deserializing:" << std::endl;
                std::cout << ex.what() << std::endl;           
            } catch (int e) {
                std::cout << "EXCEPTION " << e << std::endl; 
            }

           std::string outbound_data_ = archive_stream.str();
           // no need to use the c-style string function 'strlen'
           int len = outbound_data_.length();

           zmq::message_t msgToSend(len);
           memcpy( msgToSend.data(), outbound_data_.data(), len );

           mOutbHandlerSocket.send(msgToSend);
           std::cout << "SENT request: [" << theMsg->toString() << "]" << std::endl;
           std::cout << "LENGTH [" << len << "]" << std::endl;
         }   

        private:  
          zmq::context_t mContext;
          zmq::socket_t mOutbHandlerSocket;         
     };

CODE SNIPPET 4 (TestFE.cxx)

       #include "ZmqHandler.hxx"

       int main ()
       {
            ZmqHandler<std::string> zmqHandler;
            int counter = 1;

            while(1)
            {  
                std::string data = "Hello there!";
                GenericMessage<std::string> msg(counter, data);
                zmqHandler.sendToBE(&msg);
                counter++;
                sleep(1);
             }

             return 0;
        }

CODE SNIPPET 5 (TestBE.cxx)

       #include "zmq.hpp"
       #include "GenericMessage.hxx"
       #include <fstream>

       int main ()
       {
          //  Prepare our context and socket
          zmq::context_t context (1);
          zmq::socket_t socket (context, ZMQ_PULL);

         std::cout << "Connecting to FE..." << std::endl;
         socket.connect ("tcp://localhost:5555");

         while(1){
              zmq::message_t reply;
              socket.recv (&reply);

              const char *buf = static_cast<const char*>(reply.data());
              std::cout << "CHAR [" << buf << "]" << std::endl;

              std::string input_data_( buf, reply.size() ); 
              std::istringstream archive_stream(input_data_);
              boost::archive::text_iarchive archive(archive_stream);
              GenericMessage<std::string> theMsg;

              try
              {
                 archive >> theMsg;
              } catch (boost::archive::archive_exception& ex) {
                 std::cout << "Archive Exception during deserializing:" << std::endl;
                 std::cout << ex.what() << std::endl;           
              } catch (int e) {
                 std::cout << "EXCEPTION " << e << std::endl; 
              }

              std::cout << "ID: " << theMsg.getBeId() << std::endl;
              std::cout << "Data: " << theMsg.getData() << std::endl;

           }

            return 0;
         }

解决方案

When I build and run your code on my system, TestBE does throw the deserialization exception (every time). Here's what I did to fix it:

In your ZmqHandler class, change the method void sendToBE(GenericMessage<A> *theMsg) to void sendToBE(GenericMessage<A> theMsg). You can use a const& if you want, but you probably don't want to use a pointer here. In the same method, you need to change theMsg->XXX to theMsg.XXX, since theMsg is no longer a pointer.

In TestFE, zmqHandler.sendToBE(&msg); becomes zmqHandler.sendToBE(msg);.

If theMsg must be a pointer

In ZmqHandler, just change the line archive << theMsg to archive << *theMsg. That way, the archive's operator<< is working with the object, rather than a pointer to the object. The rest of your code can remain the same.

这篇关于追问:升压序列化定制的C ++对象越过ZeroMQ拉插座的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆