Почему возникла ошибка zmq при установке значения сериализуемого класса protobuf?

Я тестирую код, который использует zmq в качестве сокета и сетевого инструмента, а также protobuf для сериализации.

Код получает zmq_message и разбирает его в класс protobuf, взамен я меняю значение одного из членов класса и отправляю этот же класс обратно запрашивающей стороне.

Каким-то образом во время этого процесса происходит сбой утверждения zmq check(). Я действительно не знаю, почему это происходит, поскольку все выглядит хорошо для меня.

Код выглядит так в основном файле:

zmq::socket_t external(context, ZMQ_REP);
external.bind("tcp://*:29067");

zmq::message_t request;
external.recv(&request);
msg.deserialize(request);

msg.set_probed_value(12.0);
zmq::message_t response = msg.serialize();
external.send(response);

Метод десериализации выглядит следующим образом.

_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));

и метод сериализации, как показано ниже:

zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;

и set_probed_value() выглядит так:

void set_probed_value(const double& val)
{
    _msg.clear_probed();
    _msg.set_probed(val);
}

Я точно знаю, что проблема возникает, когда я устанавливаю значение probed на другое число, чем то, которое было установлено во время синтаксического анализа. Если я удалю эту строку msg.set_probed_value(12.0), никаких исключений не произойдет, и все будет в порядке.

Ошибка утверждения: проверьте () (/apps/zmq/libzmq/src/msg.cpp:347)


person apramc    schedule 25.06.2018    source источник


Ответы (2)


Подозреваемый? Нарушение опубликованных принципов ZeroMQ API

Известно, что все манипуляции с сообщениями довольно ненадежны.

Как насчет того, чтобы сначала выполнить явное копирование содержимого вместо того, чтобы напрямую манипулировать только синтаксически подслащенным reinterpret_cast<...>( msg.data() ) содержимым (на которое ссылается доставленный указатель ZeroMQ)?

Избегайте изменения содержимого сообщения после того, как сообщение было скопировано с помощью zmq_msg_copy(), это может привести к непредсказуемому поведению. Если вам нужна настоящая бумажная копия, выделите новое сообщение с помощью zmq_msg_init_size() и скопируйте содержимое сообщения с помощью memcpy().

Также рекомендуется явный close() объекта сообщения request сразу после того, как была сделана безопасная копия содержимого, как настоятельно рекомендуется опубликованная добросовестная практика проектирования в опубликованном API ZeroMQ.

Никогда не обращайтесь к элементам zmq_msg_t напрямую, вместо этого всегда используйте семейство функций zmq_msg.

API ZeroMQ явно предупреждает о том, что не следует пытаться манипулировать каким-либо содержимым сообщения каким-либо иным способом, кроме как с использованием опубликованных функций/методов API. Лучше избегать таких уловок, даже ценой чуть более длинного кода и еще нескольких SLOC-ов.

person user3666197    schedule 25.06.2018

Вы уверены, что в этом сообщении zmq msg есть завершение NULL?

_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));

Если нет, это заполнит ваш _msg мусором, поскольку он читает за конец то, что вы считаете строкой.

Причина, по которой я спрашиваю:

Когда вы создаете/отправляете сообщение, вы не включаете NULL

zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;
person James Harvey    schedule 27.06.2018