Отправить сложную структуру данных через очередь ускоренных сообщений

У меня есть следующая структура данных:

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

Используя ускоренную очередь сообщений, я попытался отправить эту структуру данных получателю очереди сообщений в другом процессе. Однако после получения у меня возникла ошибка сегментации при доступе к переменной «имя» в приведенной выше структуре.

Ниже моя функция отправителя:

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;

cout для (*recvMsg).id в порядке, но ошибка сегментации произошла при cout для (*recvMsg).name. Где-то читал, что мне нужно сделать сериализацию для структуры, но не могу понять, как это сделать. Кто-нибудь может предложить?


person tanlccc    schedule 10.09.2012    source источник


Ответы (2)


Из документа по ускорению для очереди сообщений :

Очередь сообщений просто копирует необработанные байты между процессами и не отправляет объекты. Это означает, что если мы хотим отправить объект с помощью очереди сообщений, объект должен быть двоично сериализуемым. Например, мы можем отправлять целые числа между процессами, но не 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;
            }
};

отправить.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");
}
person Vikas    schedule 10.09.2012
comment
Спасибо Викас! Пробовал читать Boost.Serialization в гугле, но так и не совсем понял :( - person tanlccc; 10.09.2012
comment
@tanlccc, я добавил для вас рабочий код. Дайте мне знать, если это поможет, или я добавлю несколько комментариев. - person Vikas; 10.09.2012
comment
Ух ты! Большое спасибо за вашу большую помощь! Последний вопрос: что, если я не знаю MAX_SIZE? Я имею в виду структуру данных, если у меня есть другая «строковая» переменная, которая может содержать неограниченное количество символов. - person tanlccc; 11.09.2012
comment
небольшая придирка: ловить исключения по константной ссылке - person BЈовић; 21.01.2014
comment
Я нахожу этот ответ очень интересным. Я хочу реализовать это, но поскольку моя структура данных сложна, а производительность является проблемой. Я хотел бы попробовать использовать бинарный архив вместо текстового. Мне нужно также использовать stringstream или есть более эффективный способ получить тот же результат с двоичными данными? - person Jepessen; 04.10.2018

Один из способов передачи сложных структур данных — сделать это по старинке — создать собственный кодировщик/декодер данных. если вы используете базовую концепцию ASN1 (Abstract Syntax Notation One), то вы можете кодировать данные в двоичное поле, затем передавать их и декодировать с помощью вашего декодера

/* Пример: Создание сообщения о событии для отправки на сервер с просьбой использовать метод MusicPlayer, передающий идентификатор транзакции и действие Start/Stop Все данные находятся в 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

person serup    schedule 03.11.2014