【问题标题】:Send complex data structure via boost message queue通过 boost 消息队列发送复杂的数据结构
【发布时间】:2012-09-03 00:43:42
【问题描述】:

我有以下数据结构:

typedef struct
{
    short id;
    string name;
    short age;
} person_struct;

使用 boost 消息队列,我尝试将此数据结构发送到另一个进程中的消息队列接收器。但是,收到后,访问上述结构中的“名称”变量时出现分段错误。

下面是我的发送函数:

person_struct MyRec;
MyRec.id = 1;
MyRec.name = "ABC123";
MyRec.age = 20;   
message_queue mqSender(create_only, "MSG_Q", 100, sizeof(person_struct));
mqSender.send(&MyRec, sizeof(person_struct), MQ_PRIORITY);

下面是我的接收函数:

message_queue myReceiver(open_only, "MSG_Q");
person_struct *recvMsg = new person_struct();
size_t msg_size;
unsigned int priority;
myReceiver.receive(recvMsg, sizeof(person_struct), msg_size, priority);
cout << "ID: " << (*recvMsg).id << endl;
cout << "Name: " << (*recvMsg).name << endl;
cout << "Age: " << (*recvMsg).age << endl;

(*recvMsg).id 的 cout 正常,但 (*recvMsg).name 的 cout 出现分段错误。在某处读到我需要对结构进行序列化,但不知道该怎么做。有人可以推荐吗?

【问题讨论】:

    标签: boost message-queue boost-interprocess


    【解决方案1】:

    来自boost doc for message queue

    消息队列只是在进程之间复制原始字节而不发送对象。这意味着如果我们想使用消息队列发送一个对象,该对象必须是二进制可序列化的。例如,我们可以在进程之间发送整数,但不能发送 std::string。您应该使用 Boost.Serialization 或使用高级 Boost.Interprocess 机制在进程之间发送复杂数据。

    使用 Boost.Serialization 序列化您的对象并在接收端反序列化。

    一些快速有效的代码:

    info.hpp

    #include <boost/serialization/string.hpp>
    
    #define MAX_SIZE 1000
    
    class info
    {
        public:
            info (int i = 0, std::string n = "")
                : id(i), name(n)
            {};
    
            int id;
            std::string name;
    
        private:
            friend class boost::serialization::access;
    
            template<class Archive>
                void serialize(Archive & ar, const unsigned int version)
                {  
                    ar & id;
                    ar & name;
                }
    };
    

    send.cpp

    #include <string>
    #include <sstream>
    
    #include <boost/interprocess/ipc/message_queue.hpp>
    #include <boost/archive/text_oarchive.hpp>
    
    #include "info.hpp"
    
    using namespace boost::interprocess;
    
    int main ()
    {
        try
        {  
            message_queue mq
                (
                 open_or_create,
                 "mq",
                 100,
                 MAX_SIZE
                );
    
            info me(1, "asdf");
    
            std::stringstream oss;
    
            boost::archive::text_oarchive oa(oss);
            oa << me;
    
            std::string serialized_string(oss.str());
            mq.send(serialized_string.data(), serialized_string.size(), 0);
        }
        catch(interprocess_exception &ex)
        {  
            std::cerr << ex.what() << std::endl;
        }
    }
    

    receive.cpp

    #include <string>
    #include <iostream>
    
    #include <boost/interprocess/ipc/message_queue.hpp>
    #include <boost/archive/text_iarchive.hpp>
    
    #include "info.hpp"
    
    using namespace boost::interprocess;
    
    int main ()
    {
        try
        {  
            message_queue mq
                (
                 open_only,
                 "mq"
                );
            message_queue::size_type recvd_size;
            unsigned int priority;
    
            info me;
    
            std::stringstream iss;
            std::string serialized_string;
            serialized_string.resize(MAX_SIZE);
            mq.receive(&serialized_string[0], MAX_SIZE, recvd_size, priority);
            iss << serialized_string;
    
            boost::archive::text_iarchive ia(iss);
            ia >> me;
    
            std::cout << me.id << std::endl;
            std::cout << me.name << std::endl;
        }
        catch(interprocess_exception &ex)
        {  
            std::cerr << ex.what() << std::endl;
        }
    
        message_queue::remove("mq");
    }
    

    【讨论】:

    • 谢谢维卡斯!我试图在 google 中阅读 Boost.Serialization 但仍然不太明白 :(
    • @tanlccc,我为你添加了一些工作代码。让我知道这是否有帮助,否则我会添加一些 cmets。
    • 哇!非常感谢您的大力帮助!最后一个问题 - 如果我不知道 MAX_SIZE 怎么办?我的意思是在数据结构中,如果我有另一个可以是无限字符的“字符串”变量。
    • 小技巧:通过 const 引用捕获异常
    • 我觉得这个答案很有趣。我想实现它,但由于我的数据结构很复杂,而且性能是一个问题。我想尝试使用二进制存档而不是文本存档。我还需要使用stringstream 或者有更有效的方法来获得与二进制数据相同的结果?
    【解决方案2】:

    传输复杂数据结构的一种方法是采用老式方式——制作您自己的数据编码器/解码器。 如果您使用 ASN1(Abstract Syntax Notation One)的基本概念,那么您可以将数据编码为二进制字段,然后将其传输并使用您的解码器进行解码

    /* 示例:创建要发送到服务器的事件消息,要求它使用 MusicPlayer 方法 传递事务 id 和动作开始/停止 所有数据都在 pCompressedData 中!!!应该发送的正是这段内存。

     // Client code
     // Create DataEncoderDecoder response
     // Encode
     DED_START_ENCODER(encoder_ptr);
     DED_PUT_STRUCT_START( encoder_ptr, "event" );
     DED_PUT_METHOD ( encoder_ptr, "name",  "MusicPlayer" );
     DED_PUT_USHORT ( encoder_ptr, "trans_id",  trans_id);
     DED_PUT_BOOL   ( encoder_ptr, "startstop", action );
     DED_PUT_STRUCT_END( encoder_ptr, "event" );
     DED_GET_ENCODED_DATA(encoder_ptr,data_ptr,iLengthOfTotalData,pCompressedData,sizeofCompressedData);
    

    //要发送的数据在pCompressedData中

     // Server code
     // retrieve data ...
     //...
    
     std::string strName,strValue;
     unsigned short iValue;
     bool bValue;
    
     DED_PUT_DATA_IN_DECODER(decoder_ptr,pCompressedData,sizeofCompressedData);
    
     // decode data ...
     if( DED_GET_STRUCT_START( decoder_ptr, "event" ) &&
     DED_GET_METHOD ( decoder_ptr, "name", strValue ) &&
     DED_GET_USHORT ( decoder_ptr, "trans_id", iValue) &&
     DED_GET_BOOL   ( decoder_ptr, "startstop", bValue ) &&
     DED_GET_STRUCT_END( decoder_ptr, "event" ))
     {
     TRACE0(_T("FAIL!!!\n"));
     }
     else
     {
     TRACE0(_T("SUCCESS!!!\n"));
     }
     */
    

    创建 DED_xxx 作为捆绑 ASN1 解决方案的基本宏!

    ASN1 info

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-30
      • 2012-10-20
      • 2017-04-27
      • 2013-04-02
      • 2023-04-10
      • 2014-03-29
      • 2018-02-02
      • 1970-01-01
      相关资源
      最近更新 更多