Google Protocol Buffers:用于C ++的parseDelimitedFrom和writeDelimitedTo

时间:2011-11-25 12:55:31

标签: c++ protocol-buffers

很抱歉再次提出这个问题,但是我们能不能一次性地发布一些与Java相匹配的C ++函数?它们似乎没有被谷歌添加,自己编写它们是一件非常痛苦的事情。以下是thisthis的一些答案。

2 个答案:

答案 0 :(得分:4)

以下是使用boost asio的两个基本版本。请注意,为了使这项工作正常,从技术上讲,在第二个版本中,需要查看缓冲区中有多少数据,计算出标头有多大(VarInt不是固定大小),但CodedInputStream有GetDirectBufferPointer,指针指向它的位置,所以从这个指针可以计算出剩余的消息大小,将它与给定的消息大小进行比较,为剩余的大小构建一个新的调整缓冲区,并为其余的大小做一个asio同步读取。信息。只要消息仍然很小(我猜大约1 kb左右),下面的工作就可以了。如果有人丢失了,请说出来。感谢。

在C ++中

writeDelimitedTo:

boost::asio::streambuf request;
{
    std::ostream request_stream(&request);

    google::protobuf::io::OstreamOutputStream raw_output (&request_stream);
    google::protobuf::io::CodedOutputStream coded_output(&raw_output);

    coded_output.WriteVarint32(myProtoMsg.ByteSize());
    myProtoMsg.SerializeToCodedStream(&coded_output);
}
boost::asio::write(socket,request);

<强> parseDelimitedFrom:

char buf[5000];
void Session::Read()
{
    boost::asio::async_read( 
        socket,
        boost::asio::buffer(buf),
        boost::asio::transfer_at_least(1),
        boost::bind(&Session::Handle_Read,shared_from_this(),boost::asio::placeholders::error));
}
void Session::Handle_Read(const boost::system::error_code& error)
{
    if (!error)
    {
        google::protobuf::io::ArrayInputStream arrayInputStream(buf,5000);
        google::protobuf::io::CodedInputStream codedInputStream(&arrayInputStream);
        uint32_t messageSize;
        codedInputStream.ReadVarint32(&messageSize);
        //Read more here
        MyProtoMsg myProtoMsg;
        myProtoMsg.ParseFromCodedStream(&codedInputStream);
    }
    Read();
}

编辑:上面有点懒(“在这里阅读更多”)。下面是一个完整的parseDelimitedFrom。欢迎任何评论。

NEW parseDelimitedFrom:

static void ReadMyVarint32(int& headerSize,int& messageSize,char buffer[])
{
    // Fast path:  We have enough bytes left in the buffer to guarantee that
    // this read won't cross the end, so we can skip the checks.
    char const* ptr = buffer;
    char b;
    uint32_t result;

    b = *(ptr++); result  = (b & 0x7F)      ; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) <<  7; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |=  b         << 28; if (!(b & 0x80)) goto done;

    // If the input is larger than 32 bits, we still need to read it all
    // and discard the high-order bits.
    for (int i = 0; i < 5; i++) {
    b = *(ptr++); if (!(b & 0x80)) goto done;
    }

    // We have overrun the maximum size of a varint (10 bytes).  Assume
    // the data is corrupt.
    headerSize = 0;
    messageSize = 0;

done:
    headerSize = ptr - buffer;
    messageSize = (int)result;
}

char buf[5000];
int receivedSize(0);
int missingSize(0);

void Session::Read()
{
    boost::asio::async_read( 
        socket,
        boost::asio::buffer(buf),
        boost::asio::transfer_at_least(1),
        boost::bind(&Session::Handle_Read,shared_from_this(),_1,_2));
}

void Session::Handle_Read(const boost::system::error_code& error,std::size_t bytes_transferred)
{
    if (!error)
    {
        int mybytes_transferred((int)bytes_transferred);
        if(missingSize == 0)
        {
            int headerSize, messageSize;
            ReadMyVarint32(headerSize,messageSize,buf);
            //std::cout << "Read new message: HeaderSize " << headerSize << " MessageSize " << messageSize << " Received: " << mybytes_transferred << std::endl;

            for(int i(0);i<mybytes_transferred-headerSize;++i)
                request[i] = buf[headerSize+i];

            missingSize = headerSize + messageSize - mybytes_transferred;
            receivedSize = mybytes_transferred - headerSize;
        }
        else
        {
            //std::cout << "Continue message: Read so far " << receivedSize << " Missing " << missingSize << " Received: " << mybytes_transferred << std::endl;
            for(int i(0);i<mybytes_transferred;++i)
                request[receivedSize+i] = buf[i];
            missingSize -= mybytes_transferred;
            receivedSize += mybytes_transferred;
        }
        if(missingSize < 0)
        {
            //Received too much, give up
            missingSize = 0;
            receivedSize = 0;
        }
        else if(missingSize == 0)
        {
            // Use your proto class here
            RequestWrapperPtr requestWrapperPtr(new RequestWrapper());
            if(requestWrapperPtr->ParseFromArray(request,receivedSize))
            {
                HandleRW(requestWrapperPtr);
            }
            else
            {
                // std::cout  << BaseString() << "Session Handle_Read: Failed to parse!";
            }
        }
        Read();
    }
}

答案 1 :(得分:1)

我知道这个问题已经回答了,但是这个问题现在已经过时了,此后对protobuf代码存储库进行了更新。

Protobuf现在在以下头文件下具有以下功能:

#include <google/protobuf/util/delimited_message_util.h>

您可以在git repo here上签出关联的cpp文件。 我已经使用boost插座试用了这些功能,它们按预期工作。