使用协议缓冲区将二进制文件从Java Server发送到C#Unity3d客户端

时间:2015-09-27 16:26:32

标签: java c# unity3d protocol-buffers protobuf-net

我问过这个问题https://stackoverflow.com/questions/32735189/sending-files-from-java-server-to-unity3d-c-sharp-client但是我发现它不是通过内置操作在Java和C#之间发送文件的最佳解决方案,因为我还需要其他消息,而不仅仅是文件内容

因此,我尝试使用Protobuf,因为它很快并且可以独立地序列化/反序列化对象平台。我的.proto文件如下:

message File{
  optional int32 fileSize = 1;
  optional string fileName = 2;
  optional bytes fileContent = 3;
}

因此,我在生成的.java文件中设置每个变量的值:

file.setFileSize(fileSize);
file.setFileName(fileName);
file.setFileContent(ByteString.copyFrom(fileContent, 0, fileContent.length);

我看过很多关于如何将对象写入文件并从中读取的教程。但是,我找不到任何关于如何将文件从服务器套接字发送到客户端套接字的示例。

我的目的是在java服务器上序列化对象(文件大小,文件名和文件内容),并将这些信息发送到C#客户端。因此,该文件可以反序列化并存储在客户端。

在上面的示例代码中,服务器读取文件的字节(图像文件)并将其写入输出流,以便客户端可以通过输入流将字节读写到磁盘。我希望通过生成.proto文件的序列化来实现相同的功能。

任何人都可以给我一个例子,或者给我一个如何做到这一点的提示吗?

1 个答案:

答案 0 :(得分:0)

documentation中所述,protobuf不会处理消息的开始和停止位置,因此在使用像TCP这样的流套接字时,您必须自己完成。

来自doc:

  

[...]如果要将多条消息写入单个文件或流,则需要跟踪一条消息的结束位置和下一条消息的开始位置。协议缓冲区有线格式不是自定界限的,因此协议缓冲区解析器无法确定消息自身的结束位置。解决此问题的最简单方法是在编写消息本身之前写入每条消息的大小。当您重新读取消息时,读取​​大小,然后将字节读入单独的缓冲区,然后从该缓冲区解析。 [...]

长度前缀是一个很好的候选者。根据您正在编写的语言,有些库可以为例如长度添加前缀。您可以使用的TCP,或者您可以自己定义。

线路上缓冲区的示例表示可能是格式(左侧缓冲区的开头):

[buf_length|serialized_buffer2]

所以你编码在发送之前打包缓冲区可能看起来像(这是在带有node.js的javascript中):

function pack(message) {
  var packet = new Buffer(message.length + 2);

  packet.writeIntBE(message.length, 0, 2);
  message.copy(packet, 2);

  return packet;
}

要阅读,你必须做相反的事情:

client.on('data', function (data) {
  dataBuffer = Buffer.concat([dataBuffer, data]);

  var dataLen = dataBuffer.readIntBE(0, 2);

  while(dataBuffer.length >= dataLen) {
    // Message length excluding length prefix of 2 bytes
    var msgLen = dataBuffer.readIntBE(0, 2);

    var thisMsg = new Buffer(dataBuffer.slice(2, msgLen + 2));

    //do something with the msg here

    // Remove processed message from buffer
    dataBuffer = dataBuffer.slice(msgLen + 2);
  }
});

您还应该知道,在TCP套接字上发送多个protobufs时,它们可能会被缓冲以进行网络优化(连接)并一起发送。这意味着无论如何都需要某种分隔符。