0

私は、クライアント用の c# とサーバー用の c++ で Protobuf3 を利用しています。.proto は、対応する protoc3 コンパイラから生成されます。私は現在、クライアントから送信されたサーバー上の受信バイトを再解析して、元の google::protobuf::Message に戻す方法を見つけようとしています。私のC ++サーバー上のオブジェクト。

私のクライアントは 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;
}

私の計画は、できればすべてのメッセージを BaseMessage から拡張して、最終的に特定のメッセージを識別できるようにすることです。解析と再解析を理解したら。

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# クライアントの送信段階で設定された正しい値ではないことに由来します。

4

1 に答える 1

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

なぜ追加する必要があるのか​​ については、まだ少し疑問があります。nullターミネータと関係があるに違いないと思います。ただし、この追加がない場合、私のメッセージは次のようになります。#\u0012!\n\u001Ftype.googleapis.com/server.Pin

次に、追加で行うように見えるのは、アドオンだけが正しいメッセージです:#\u0012!\n\u001Ftype.googleapis.com/server.Ping

また、このプロセス中に、protobuf3 Any 型を利用してメッセージを分類する方法を見つけました。私のBaseMessageは次のように定義されています:

syntax = "proto3";

package base;

import "google/protobuf/any.proto";

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

これにより、任意の種類の google::protobuf::Message を msg フィールドに配置できます。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);
    }
  }
于 2016-07-24T00:58:55.600 に答える