2016-07-23 3 views
0

Я использую Protobuf3 с C# для моего клиента & C++ для моего сервера, где .proto создаются из соответствующего компилятора protoc3. Я новичок в использовании буферов протокола Google, где в настоящее время я пытаюсь выяснить, как повторно разобрать полученные байты на моем сервере, которые были отправлены от моего клиента, чтобы вернуть его обратно в исходную версию google :: protobuf :: Message объект на моем сервере C++.Получение сообщения Protobuf3 по сети

Мой клиент посылает CodedOutputStream в C#:

public PacketHandler() 
{ 
    m_client = GetComponent<ClientObject>(); 
    m_packet = new byte[m_client.GetServerConnection().GetMaxPacketSize()]; 
    m_ostream = new BinaryWriter(new MemoryStream(m_packet)); 
} 

public void DataToSend(IMessage message) 
{ 
    CodedOutputStream output = new CodedOutputStream(m_ostream.BaseStream, true); 
    output.WriteMessage(message); 
    output.Flush(); 
    m_client.GetServerConnection().GetClient().Send(m_packet, message.CalculateSize()); 
} 

Это, кажется, работает, то сообщение, которое посылается прямо сейчас является простой Ping сообщение, которое выглядит следующим образом:

// Ping.proto 
syntax = "proto3"; 
package server; 

import "BaseMessage.proto"; 

message Ping { 
    base.BaseMessage base = 1; 
} 

message Pong { 
    base.BaseMessage base = 1; 
} 

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

// BaseMessage.proto 
syntax = "proto3"; 

package base; 

message BaseMessage { 
    uint32 size = 1; 
} 

Мой план состоит в том, чтобы надеяться, что все мои мэсы ges из BaseMessage, чтобы в конечном итоге определить идентификацию конкретного сообщения. Как только я получу синтаксический анализ &, повторный анализ разобрался.

Полученное сообщение, что я получаю на мой C++ стороне сервера выглядит следующим образом: \ u0004 \ п \ u0002 \ б

При получении сообщения я пытающийся повторно анализировать с помощью объекта CodedInputStream, пытаясь проанализировать полученные байты.

PacketHandler::PacketHandler(QByteArray& packet, const Manager::ClientPtr client) : 
    m_packet(packet), 
    m_client(client) 
{ 
    //unsigned char buffer[512] = { 0 }; 
    unsigned char data[packet.size()] = { 0 }; 
    memcpy(data, packet.data(), packet.size()); 

    google::protobuf::uint32 msgSize; 
    google::protobuf::io::CodedInputStream inputStream(data, packet.size()); 
    //inputStream.ReadVarint32(&msgSize); 
    //inputStream.ReadRaw(buffer, packet.size()); 
    server::Ping pingMsg; 
    pingMsg.ParseFromCodedStream(&inputStream); 
    qDebug() << pingMsg.base().size(); 
} 

Здесь я немного не уверены в процессе, который нуждающейся быть сделано, чтобы повторно разобрать сообщение в конкретном сообщении. Я считаю, что если я использую BaseMessage, который расширяет все сообщения, которые позволят мне идентифицировать конкретное сообщение, чтобы я знал, какой из них нужно создать. Однако в этом текущем тесте, где я знаю, что это будет сообщение Ping, ParseFromCodedStream, похоже, не создает оригинальное сообщение. Мое рассуждение происходит во время моего qDebug(), pingMsg.base(). Size() не является правильным значением, которое было установлено на этапе отправки в моем клиенте C#.

ответ

0

Я был в состоянии получить это решить приращением мой послал количество байт на + 1.

public void DataToSend(IMessage message) 
{ 
    CodedOutputStream output = new CodedOutputStream(m_ostream.BaseStream, true); 
    output.WriteMessage(message); 
    output.Flush(); 
    (m_ostream.BaseStream as MemoryStream).SetLength(0); // reset stream for next packet(s) 
    m_client.GetServerConnection().GetClient().Send(m_packet, message.CalculateSize() + 1); 
} 

Я еще немного подозреваемого, почему мне нужно добавить один. Я думаю, что это должно быть связано с нулевым терминатором. Однако перед без этого добавления мое сообщение будет выглядеть следующим образом: #\u0012!\n\u001Ftype.googleapis.com/server.Pin

Затем с добавлением все это, кажется, сделать, это добавить на это правильное сообщение: #\u0012!\n\u001Ftype.googleapis.com/server.Ping

Кроме того, в ходе этого процесса я понял, как классифицировать мой сообщения, использующие protobuf3 Любой тип. Где сейчас моя BaseMessage определяется как:

syntax = "proto3"; 

package base; 

import "google/protobuf/any.proto"; 

message BaseMessage { 
    uint32 size = 1; 
    google.protobuf.Any msg = 2; 
} 

, который позволяет мне разместить какой-либо Google :: Protobuf :: Сообщение в поле сбще, где на ParsingFromCodedStream я могу проверить, если это то, что конкретное сообщение.

PacketHandler::PacketHandler(QByteArray& packet, const Manager::ClientPtr client) : 
    m_packet(packet), 
    m_client(client) 
    { 
    unsigned char data[packet.size()] = { 0 }; 
    memcpy(data, packet.data(), packet.size()); 

    google::protobuf::io::CodedInputStream inputStream(data, packet.size()); 
    // read the prefixed length of the message & discard 
    google::protobuf::uint32 msgSize; 
    inputStream.ReadVarint32(&msgSize); 
    // ----- 
    // collect the BaseMessage & execute functionality based on type_url 
    base::BaseMessage msg; 
    if (!msg.ParseFromCodedStream(&inputStream)) 
    { 
     qDebug() << msg.DebugString().c_str(); 
     return; 
    } 

    if (msg.msg().Is<server::Ping>()) 
    { 
     server::Ping pingMsg; 
     msg.msg().UnpackTo(&pingMsg); 
    } 
    } 
+0

Буферы протокола Google не формируют его сообщения, что делает его раздражающим для потока. В принципе, вы должны использовать что-то помимо GPB, чтобы разграничить одно сообщение от другого. Что-то вроде ZeroMQ очень полезно в этом отношении. Это более привлекательный способ сделать это, чем отправить размер сообщения - проще получить истинную синхронизацию между отправителем и получателем. – bazza