C++ Linux Google Protobuf + boost::asio 无法解析

C++ Linux Google Protobuf + boost::asio Cannot Parse

我正在尝试通过 TCP 通过 boost::asio 套接字发送 Google Protobuf 消息。我认识到 TCP 是一种流式传输协议,因此我在消息通过套接字之前对其执行长度前缀。我有代码工作,但它似乎只在某些时候工作,即使我重复相同的调用而不改变环境。有时我会收到以下错误:

[libprotobuf ERROR google/protobuf/message_lite.cc:123] Can't parse message of type "xxx" because it is missing required fields: Name, ApplicationType, MessageType

原因很容易理解,但我无法挑出为什么这只是偶尔发生并且大多数时候解析得很好。只需让一个客户端与服务器通信并简单地重新启动进程,就很容易重现错误。

下面是套接字代码片段。

const int TCP_HEADER_SIZE = 8;

发件人:

bool Write(const google::protobuf::MessageLite& proto) {
    char header[TCP_HEADER_SIZE];
    int size = proto.ByteSize();
    char data[TCP_HEADER_SIZE + size];
    sprintf(data, "%i", size);
    proto.SerializeToArray(data+TCP_HEADER_SIZE, size);
    boost::asio::async_write(Socket, 
                             boost::asio::buffer(data, TCP_HEADER_SIZE + size),
                             boost::bind(&TCPSender::WriteHandler, 
                                         this, _1, _2));
}

接收方:

std::array<char, TCP_HEADER_SIZE> Header;
std::array<char, 8192> Bytes;

void ReadHandler(const boost::system::error_code &ec, 
                 std::size_t bytes_transferred) {
    if(!ec) {
        int msgsize = atoi(Header.data());
        if(msgsize > 0) {
            boost::asio::read(Socket, boost::asio::buffer(Bytes,static_cast<std::size_t>(msgsize)));
            ReadFunc(Bytes.data(), msgsize);
        }
        boost::asio::async_read(Socket, boost::asio::buffer(Header, TCP_HEADER_SIZE),
                                boost::bind(&TCPReceiver::ReadHandler, this, _1, _2));
    }
    else {
        std::cerr << "Server::ReadHandler::" << ec.message() << '\n';
    }
}

ReadFunc:

void HandleIncomingData(const char *data, const std::size_t size) {
    xxx::messaging::CMSMessage proto;
    proto.ParseFromArray(data, static_cast<int>(size));
}

我应该提一下,我需要它尽可能快,所以任何优化也将不胜感激。

程序调用未定义的行为,因为它未能满足 boost::asio::async_write()buffers 参数的生命周期要求:

[...] ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.

Write() 函数中,boost::asio::async_write() 将立即 return,并可能导致 data 在异步写入操作完成之前超出范围。要解决此问题,请考虑延长底层缓冲区的生命周期,例如通过将缓冲区与操作相关联并在处理程序中执行清理,或者使缓冲区成为 TCPSender.

上的数据成员