2013-01-28 3 views
1

Текст, который я пишу здесь, является проблемой, которую я открыл ранее в другом потоке в Boost: Serializing/De-serializing a custom C++ object passed over ZeroMQ pull socket. Проблемы компиляции в более раннем потоке были решены с использованием типа textarchive, а не binaryarchive, но теперь я испытываю проблему во время выполнения при де-сериализации. Повторяю здесь более ранний текст с новым описанием проблемы для вашего удобства. Я относительно новичок в области C++ и ценю любую дальнейшую помощь.Boost: Де-сериализация пользовательского объекта C++, переданного через гнездо ZeroMQ pull

Описание:

У меня есть класс C++ с именем GenericMessage, который просто содержит идентификатор и данные в качестве его членов (см фрагмент кода 2 ниже - GenericMessage.hxx). Мое намерение состоит в том, чтобы сериализовать экземпляр этого класса и отправить его через сокет ZeroMQ, который реализует шаблон push.

Сериализация и отправляющая задача была реализована в классе ZMQHandler (см функцию sendToBE), которая помещается в имени ZMQHandler.hxx заголовочного файла, показанного в фрагменте кода 3 ниже. Этот класс создается через TestFE.cxx показан в 4-й фрагмент кода ниже.

Принимающие и де-сериализация экземпляра GenericMessage реализуются в TestBE.cxx доступны в пятого фрагменте кода ниже. Мое намерение состоит в том, чтобы получить экземпляр GenericMessage через сокет ZMQ (т. Е. Pull socket), де-сериализовать его, а затем распечатать его элементы до стандартного вывода.

Постановка задачи:

Когда я запускаю приемник (т.е. TestBE.cxx) Я проверить здесь, что я могу передать данные из TestFE.cxx в TEstBE.cxx над гнездом ZMQ. Однако я получил исключение, указанное в первом фрагменте кода ниже, когда я пытаюсь де-сериализовать входной архив по строке 28 в TestBE.cxx (см. Пятый фрагмент кода очень ниже, строка 28 отмечена).

Есть ли что-то, что мне не хватает в этой процедуре де-сериализации, реализованной в TestBE.cxx в фрагменте кода 5? Почему вы думаете, что я получаю это исключение? Может быть, мне не хватает st в процедуре сериализации, реализованной в ZMQHandler.cxx (фрагмент кода 3 - функция sendToBE). Заранее спасибо.

КОД SNIPPET 1 GDB ВЫВОД & трассировку

$ gdb TestBE 
GNU gdb (GDB) 7.5-ubuntu 
..... 
(gdb) r 
Starting program: /TestBE 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1". 
[New Thread 0xb7c12b40 (LWP 16644)] 
[New Thread 0xb7411b40 (LWP 16645)] 
Connecting to FE... 

!!!!!!!!!!!!!!!!!!!! ЗДЕСЬ НАЧИНАЕТСЯ !!!!!!! !!!!!!!!!!!!!!!!!!!!

**CHAR [22 serialization::archive 9 0 1 0 
0 1 12 Hello there!] 
terminate called after throwing an instance of 'std::logic_error' 
what(): basic_string::_S_construct null not valid** 

!!!!!!!!!!!!!!!!!!!! ЗДЕСЬ END !!!!!!!!!!!!!!!!!!! !!!!!!!!

Program received signal SIGABRT, Aborted. 
0xb7fdd424 in __kernel_vsyscall() 
(gdb) bt 
#0 0xb7fdd424 in __kernel_vsyscall() 
#1 0xb7c7a1df in raise() from /lib/i386-linux-gnu/libc.so.6 
#2 0xb7c7d825 in abort() from /lib/i386-linux-gnu/libc.so.6 
#3 0xb7e608ad in __gnu_cxx::__verbose_terminate_handler()() from /usr/lib/i386- linux-gnu/libstdc++.so.6 
#4 0xb7e5e4f3 in ??() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#5 0xb7e5e52f in std::terminate()() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#6 0xb7e5e825 in __cxa_rethrow() from /usr/lib/i386-linux-gnu/libstdc++.so.6 
#7 0x0804c1d4 in boost::archive::detail::pointer_iserializer<boost::archive::text_iarchive, GenericMessage<std::string> >::load_object_ptr (this=0x8054444, ar=..., 
[email protected]: 0x805cb50, file_version=0) at /usr/include/boost/archive/detail/iserializer.hpp:327 
#8 0xb7f3839d in boost::archive::detail::basic_iarchive::load_pointer(void*&, boost::archive::detail::basic_pointer_iserializer const*, boost::archive::detail::basic_pointer_iserializer const* (*) (boost::serialization::extended_type_info const&))() from /usr/lib/libboost_serialization.so.1.49.0 
#9 0x0804bea9 in boost::archive::detail::load_pointer_type<boost::archive::text_iarchive>::invoke<GenericMes  sage<std::string>*> (ar=..., [email protected]: 0xbfffeff8) 
at /usr/include/boost/archive/detail/iserializer.hpp:524 
#10 0x0804be55 in boost::archive::load<boost::archive::text_iarchive,         GenericMessage<std::string>*> (ar=..., [email protected]: 0xbfffeff8) 
at /usr/include/boost/archive/detail/iserializer.hpp:592 
#11 0x0804be36 in boost::archive::detail::common_iarchive<boost::archive::text_iarchive>::load_override<Gener icMessage<std::string>*> (this=0xbfffef84, [email protected]: 0xbfffeff8) 
    at /usr/include/boost/archive/detail/common_iarchive.hpp:66 
#12 0x0804be14 in boost::archive::basic_text_iarchive<boost::archive::text_iarchive>::load_override<GenericMe ssage<std::string>*> (this=0xbfffef84, [email protected]: 0xbfffeff8) 
    at /usr/include/boost/archive/basic_text_iarchive.hpp:65 
#13 0x0804bdf2 in boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::load_override<GenericMes sage<std::string>*> (this=0xbfffef84, [email protected]: 0xbfffeff8) 
    at /usr/include/boost/archive/text_iarchive.hpp:82 
#14 0x0804bcec in  boost::archive::detail::interface_iarchive<boost::archive::text_iarchive>::operator>> <GenericMessage<std::string>*> (this=0xbfffef84, [email protected]: 0xbfffeff8) 
at /usr/include/boost/archive/detail/interface_iarchive.hpp:60 
#15 0x0804b2a1 in main() at TestBE.cxx:28 

фрагмент кода 2 (GenericMessage.HXX)

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

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

    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 ret; 
    } 

    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(); 
    const char * buf = outbound_data_.c_str();  
    int len = strlen((const char*)buf); 
    std::cout << "LENGTH [" << len << "]" << std::endl; 

    zmq::message_t msgToSend(len); 

    memcpy ((char *) msgToSend.data(), buf, len); 

    if(memcmp((char *) msgToSend.data(), buf, len) != 0) 
    { 
    std::cout << "memcpy error!" << std::endl; 
    } 

    mOutbHandlerSocket.send(msgToSend); 
    std::cout << "SENT request: [" << theMsg->toString() << "]" << 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!\0"; 
     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); 
     std::istringstream archive_stream(input_data_); 
     boost::archive::text_iarchive archive(archive_stream); 
     GenericMessage<std::string> *theMsg; 

     try 
     { 
     /* !!!!!!!!!! LINE 28 is the following !!!!!!!!!!*/ 
     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; 
    } 

ответ

0

Вы указали theMsg в качестве указателя (GenericMessage<std::string> *theMsg;).

Попробуйте изменить эту строку в GenericMessage<std::string> theMsg; .`

Реальный источник вашего исключения

В конструктор по умолчанию GenericMessage, инициализации data с NULL. Однако вы не можете инициализировать std::string указателем NULL. Не инициализируйте свой член data в конструкторе по умолчанию.

GenericMessage() 
: beId(-1) 
{} 

Пока ваш тип T имеет конструктор по умолчанию, компилятор будет обрабатывать инициализацию, когда шаблон генерируется.

(надеюсь) Полезный совет # 1

Буфер данных в zmq::message_t есть (в целом) не нуль. После получения сообщения будьте осторожны, как конвертировать буфер в строку.

// snip 
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); // assumes a null-term string 
std::string input_data_(buf, reply.size()); 
// snip 

(надеюсь) Полезный совет # 2

Кроме того, я заметил что-то в ZmqHandler.hxx.

// snip 
std::string outbound_data_ = archive_stream.str(); 
const char * buf = outbound_data_.c_str();  
int len = strlen((const char*)buf); 
std::cout << "LENGTH [" << len << "]" << std::endl; 

zmq::message_t msgToSend(len); 

memcpy ((char *) msgToSend.data(), buf, len); 

if(memcmp((char *) msgToSend.data(), buf, len) != 0) 
{ 
    std::cout << "memcpy error!" << std::endl; 
} 
// snip 

Вам не нужно проверять результаты memcpy (если вы не хотите проверить его возвращаемое значение). Весь блок можно было бы изменить примерно так:

std::string outbound_data_ = archive_stream.str(); 
// no need to use the c-style string function 'strlen' 
int len = outbound_data_.length(); 
std::cout << "LENGTH [" << len << "]" << std::endl; 

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

Спасибо за ответ, но я все еще получаю сообщение об ошибке, о котором я упомянул ранее в первом фрагменте кода выше. Может ли быть еще больше? –

+0

Думаю, я сейчас это вижу. Я добавлю еще одно изменение в свой ответ. –

+0

Спасибо. Теперь он работает, но с некоторыми другими проблемами. В последних двух строках TestBE.cxx, где я печатаю идентификатор и данные объекта GeNericMessage, я ничего не получил для поля данных. Кроме того, появляются некоторые символы с вопросительными знаками, где я печатаю содержимое переданной строки. Вы знаете, почему это происходит? Большое спасибо. 0 39 12 Привет!] ID0 данных –