简体   繁体   中英

Googles ProtoBuf on C++ chatting with Protobuf-net on C# (UDP)

I have a big problem concerning those both Protobufs.

I have a Server/Client Application on C++ using Googles Protobuf. It works quite well.

The Client sends the Data to the Server which should distribute this Message to the other Clients.

The C++ Client is a pure sender, packing the Protobuf-Struct in a Char-Array with fixed size (500 atm).

The C++ Server deserializes it, looks for the Command (Login Logout or a Message to others), and (if its a Message) sends it to the C#-Client. This is done also by a fixed size of 500 chars.

This works quite well. Now on the C# side:

The C# client atm can log in and send Messages with Protobuf-net. This works quite brilliant even though Protobuf-Net packs it in a byte-Array (which is unsigned unlike the char-array on c++-Side) with dyanamic size. Even so the server recognizes the Message and prints it out.

BUT (and here is the freaking problem) when the server forwards a message from the c++-Client I get big problems in C#.

For the Note: The client is implemented in Unity3D.

Unity receives the Byte-Array almost fine. One thing to note is that the Byte-Array is unsigned unlike the Message sent by the server. This leads to -1 become 255.

C#-Code:

sock.ReceiveFrom (incoming, ref otherEnd);    
SendPack message;
using(System.IO.MemoryStream ms = 
new System.IO.MemoryStream(incoming)){
    message = ProtoBuf.Serializer.Deserialize<SendPack>(ms);
    print (message);
    ms.Flush();
    ms.Close();
}

This is the C# Client.

C++-Code:

char buffer[BUF];
package.serializeToArray(buffer,500);
int n = sendto(sock,buffer,BUF,0,(struct sockaddr*)
&serverAddr,sizeof(serverAddr));

This is the C++-Client

The C++-Server just forwards the char-Array to the C#-client, which is the same as the UDP-Client without the serialize-part.

I Get Errors like: ProtoException: Invalid field in source data: 0

or Invalide wire-type

edit: This is the Proto-File

syntax = "proto2"; package Messages;

message SendPack {
  required int32 command = 1;
  required string name = 2;
  repeated RobotPart content = 3;

}

message RobotPart {
required float yaw = 1;
required float pitch = 2;
required float roll = 3;
}

For C++ I use the normal Proto-Compiler For C# I use -Net compiler to create a CS-File then Build libary from it, with reference to ProtoBuf.dll for unity and then let the precompiler make a Serialize.dll to include in Unity3D

Ok, I reread your code better. I think the problem may be related on the way you handle the c# server. I think you should try this approach:

MemoryStream stream = new MemoryStream(incoming, false);
ModelSerializer serializer = new ModelSerializer(); message = (SendPack) serializer.Deserialize (stream, incoming, typeof (incoming));

All right. I found the Answer now.

Protobuf-Net has real problems if the incoming Message has a fixed length (in my case 500) if its not the exact byte size of the Protobuf.

I modified my C++-Server this way:

int size = package.ByteSize();
char message[size];
package.SerializeToArray(message,size);

And then send it with this size.

As I mentioned in my OP, the C++ version can handle messages that are packed into fix sized arrays and decode them.

Now on the C#-Part I need to do a little work around.

I still receive a message and put it in a fix sized byte-array. If I just use an uninitialized array, I get errors.

int s = sock.ReceiveFrom (incoming, ref otherEnd);
SendPack message = new SendPack();
using(System.IO.MemoryStream ms = new System.IO.MemoryStream(incoming,0,s)){
    SendPackSerializer sps = new SendPackSerializer();
    message = (SendPack)sps.Deserialize(ms,null,typeof(SendPack));
    print (message);
    ms.Flush();
    ms.Close();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM