5

これは、以前Boost: De-serializing a custom C++ object passed over ZeroMQ pull socketの別のスレッドで開いたフォローアップの問題です。そのスレッドの問題は、提供された回答に基づいて解決されました。今、実行時に別の問題があります。以下の説明を参照してください。私は C++ の領域にまったく慣れていないので、問題の説明の下で説明したことに加えて、提供されたコードの任意の部分を改善する必要があることを教えていただければ幸いです。

説明:

ID とデータをメンバーとして保持するGenericMessageという名前の C++ クラスがあります (以下のコード スニペット 2 - GenericMessage.hxx を参照)。私の意図は、このクラスのインスタンスをシリアル化し、プッシュ パターンを実装する ZeroMQ ソケット経由で送信することです。

シリアル化および送信タスクは、以下のコード スニペット 3に示すヘッダー ファイル名 ZMQHandler.hxx に配置されるクラス ZMQHandler (sendToBE 関数を参照) に実装されています。このクラスは、以下の 4 番目のコード スニペットに示されているTestFE.cxxによってインスタンス化されます。

GenericMessage インスタンスの受信と逆シリアル化は、以下 の5 番目のコード スニペットにあるTestBE.cxxに実装されています。私の意図は、ZMQ ソケットを介して GenericMessage インスタンスを受信し (つまり、ソケットをプルする)、それを逆シリアル化し、そのメンバーを標準出力に出力することです。

シリアル化と、ZeroMQ ソケットを介して転送される GenericMessage オブジェクトが正常に動作することを確認しました。逆シリアル化も機能しているようで、例外やセグメンテーション違反のようなものは発生しません。

問題文:

TestBE.cxx のコード (コード スニペット 5 を参照) から期待されることは、ZeroMQ ソケットを介して GenericMessage オブジェクトを受信し、それを逆シリアル化し、その 2 つのメンバー、つまりこの場合は文字列オブジェクトである id と data を出力することです。より正確には、最初に取得した char ストリームのコンテンツを出力し、次に逆シリアル化されたオブジェクトのメンバーを出力する必要があります。代わりに、これらのメンバーをまったく出力しません。アル、クエスチョン マークを含む奇妙な記号を受信した char ストリームに入れます。以下の最初のコード スニペットを参照してください。私の要点がわかります。

質問:

i)期待される出力が得られないのはなぜですか? 出力に奇妙な記号でマークされた質問が表示されるのはなぜですか? 印刷された char ストリームには表示されているのに、なぜ id フィールドと data フィールドが表示されないのですか?

ii) GenericMessage クラスのデータ フィールドは、テスト目的で std::string に設定されたテンプレート タイプです。ただし、実際の使用では、より複雑なオブジェクトをシリアル化された形式で転送する予定です。この点で、クラス boost::archive::text_iarchive および boost::archive::text_oarchive の使用は有用だと思いますか。代わりにバイナリを使用する必要がありますか? もしそうなら、私が知っておくべきだと思われる落とし穴/潜在的な問題はありますか? 前もって感謝します。

スニペット 1: プログラムの出力と期待される出力

  *******************
  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: 

コード スニペット 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;
    }

   };

コード スニペット 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;         
     };

コード スニペット 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;
        }

コード スニペット 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;
         }
4

1 に答える 1

1

システムでコードをビルドして実行すると、TestBE(毎回) 逆シリアル化例外がスローされます。これを修正するために私がしたことは次のとおりです。

ZmqHandlerクラスで、メソッドvoid sendToBE(GenericMessage<A> *theMsg)をに変更しますvoid sendToBE(GenericMessage<A> theMsg)。必要に応じて a を使用できますconst&が、おそらくここではポインターを使用したくないでしょう。はポインターではないため、同じメソッドで に変更theMsg->XXXする必要があります。theMsg.XXXtheMsg

TestFEで、 になりzmqHandler.sendToBE(&msg);ますzmqHandler.sendToBE(msg);

theMsgポインターでなければならない場合

で、行を にZmqHandler変更するだけです。そうすれば、アーカイブはオブジェクトへのポインターではなく、オブジェクトを操作します。コードの残りの部分は同じままでかまいません。archive << theMsgarchive << *theMsgoperator<<

于 2013-02-01T18:14:57.397 に答える