2016-07-23 114 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