2014-05-15 3 views
2

У меня проблема с отправкой zmq-сообщения, построенного из указателя на struct, который содержит другую структуру.Отправка структуры, содержащей другую структуру, как сообщение ZeroMQ

Серверный код:

#include <zmq.hpp> 
#include <string> 
#include <iostream> 

using namespace zmq; 
using namespace std; 

struct structB{ 
    int a; 
    string c; 
}; 

struct structC{ 
    int z; 
    struct structB b; 
}; 

int main() 
{ 
    context_t context(1); 
    socket_t *socket = new socket_t(context,ZMQ_REP); 
    socket->bind("tcp://*:5555"); 

    message_t *request = new message_t(); 
    socket->recv(request); 

    struct structB messageB; 
    messageB.a=0; 
    messageB.c="aa"; 

    struct structC *messageC = new struct structC; 
    messageC->z = 4; 
    messageC->b = messageB; 

    char *buffer = (char*)(messageC); 
    message_t *reply = new message_t((void*)buffer, 
         +sizeof(struct structB) 
         +sizeof(struct structC) 
         ,0); 
    socket->send(*reply); 

    return 0; 
} 

код клиента:

#include <zmq.hpp> 
#include <iostream> 
#include <string> 

using namespace std; 
using namespace zmq; 

struct structB{ 
    int a; 
    string c; 
}; 

struct structC{ 
    int z; 
    struct structB b; 
}; 

int main() 
{ 
    context_t context(1); 
    socket_t *socket = new socket_t(context,ZMQ_REQ); 
    socket->connect("tcp://*:5555"); 

    const char* buffer = "abc"; 
    message_t *request = new message_t((void*)buffer,sizeof(char*),0); 
    socket->send(*request); 

    message_t *reply = new message_t; 
    socket->recv(reply); 

    struct structC *messageC = new struct structC; 
    messageC = static_cast<struct structC*>(reply->data()); 

cout<<messageC->b.a<<endl;//no crash here 

    struct structB messageB = messageC->b;//Segmentation fault (core dumped) 

    return 0; 
} 

Эта программа падает, когда я пытаюсь использовать строку под названием "с" от structB. Не имеет значения, пытаюсь ли я его распечатать или назначить целую структуру structB, как в приведенном выше примере.

Где проблема? Должен ли я создавать ответ на message_t * на стороне сервера по-разному?

+0

У вас есть странное сочетание синтаксиса C и C++ (в C, struct - это отдельное пространство имен и при использовании используется ключевое слово 'struct', но в C++ они этого не делают. Почему вы _sometimes_ его используете?) И аналогично странный микс объектов-стеков и кучи (почему вы создаете 'messageB' в стеке и' messageC' на куче? 'messageC' также может быть создано в стеке. И' messageB' является частью 'messageC'; вам не нужно отдельный экземпляр.) –

ответ

3

Вы не можете отправить string по сети, так как std::string - это контейнер. Вы можете использовать flexible array member или массив большого размера или написать небольшой класс, который равен serializable (вам нужно написать код для подготовки буфера) для отправки данных.

Когда вы struct structB messageB = messageC->b; члены указателя std::string элемента встраивать в messageC-> б может быть разыменовать в конструкторе копирования или std::string, который, возможно, вызывает ошибку сегментации.

Пример большой массив символов будет:

struct structB{ 
    int a; 
    char c[MAX_LENGTH]; 
}; 

Позже

struct structB messageB; 
messageB.a=0; 
strcpy(messageB.c,"aa"); // #include<cstring> or use std::copy from <algorithm> 

struct structC *messageC = new struct structC; 
// I guess you want this(not sure) messageC->z = static_cast<int>(sizeof(int) + strlen(messageB) + 1); 
messageC->z = 4; 
messageC->b = messageB; 

А потом

const int length = sizeof(int) /* z */ + sizeof(int) /* a */ + strlen("aa") + 1; 
zmq::message_t msg (length); 
memcpy (msg.data(), &messageC, length); 
socket->send(msg); 

Эти некоторые изменения, необходимые на стороне сервера, вы должны сделать подобное изменения на стороне клиента также.

В качестве побочного примечания ваш код очень грязный, не развертывайте его в больших приложениях, прежде чем разбирать несколько вещей, например удаление ненужного new и правильное представление вложенных структур.

+1

Я бы настоятельно рекомендовал использовать что-то вроде [Google Protobuf] (https://code.google.com/p/protobuf/) или [Boost.Serialization] (http://www.boost.org/libs /serialization/doc/index.html) для обработки сериализации. Это звучит как излишество для игры вокруг, но даже прототипы отбрасывания часто заканчиваются тем, что они используются задолго до их ожидаемого срока службы, и когда он растет или когда ему нужно изменить, хорошая библиотека сериализации поможет много поддерживать код. –

+0

@JanHudec Я полностью согласен с вами. –

2

Ваши структуры не POD. Класс «string» не может быть скопирован как куча памяти. Существует проблема.

Используйте c.c_str() и c.size() для копирования в виде блока памяти.

Смежные вопросы