2016-07-23 83 views
0

我正在为我的客户端使用Protobuf3和c#& C++用于我的服务器,其中.proto是从相应的protoc3编译器生成的。我是使用Google协议缓冲区的新手,目前我正试图弄清楚如何重新解析从我的客户端发送来的服务器上接收到的字节,以将其重新转换为它的原始google :: protobuf :: Message对象在我的C++服务器上。通过网络接收Protobuf3消息

我的客户端发送C#中的CodedOutputStream:

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; 
} 

我的计划是希望将所有messa基本消息中的ges以便最终识别特定的消息。一旦我得到解析&重新解析了。

,我在我的C获取收到的消息++服务器端是这样的:\ U0004 \ n \ U0002 \ b

当试图接收我试图使用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); 
} 

解决,通过增加我的SENT字节计数我还是有点怀疑,为什么我需要添加一个。我认为它必须与一个空终止符。这除了但是之前没有能看我的消息,如:#\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; 
} 

,让我把任何类型的谷歌:: 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

谷歌协议缓冲区没有框架它的消息,使它很烦人的流。基本上你必须使用GPB以外的东西来划分另一个消息。像ZeroMQ这样的东西在这方面非常有用。与发送消息大小相比,这是一种更有趣的方式 - 在发送者和接收者之间实现真正的同步更容易。 – bazza