系统相关
首页 > 系统相关> > C Linux Google Protobuf boost :: asio无法解析

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

作者:互联网

我正在尝试通过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()将立即返回,并有可能导致数据在异步写入操作完成之前超出范围.要解决此问题,请考虑延长基础缓冲区的寿命,例如,通过将缓冲区与操作相关联并在处理程序中执行清理,或将缓冲区设为TCPSender上的数据成员.

标签:tcp,protocol-buffers,boost-asio,linux,c-4
来源: https://codeday.me/bug/20191120/2040297.html