简体   繁体   English

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

[英]Send binary file from Java Server to C# Unity3d Client with Protocol Buffer

I have asked this question https://stackoverflow.com/questions/32735189/sending-files-from-java-server-to-unity3d-c-sharp-client but I saw that it isn't an optimal solution to send files between Java and C# via built-in operations, because I also need also other messages, not only the file content. 我问了这个问题https://stackoverflow.com/questions/32735189/sending-files-from-java-server-to-unity3d-c-sharp-client但我发现这不是发送文件的最佳解决方案通过内置操作在Java和C#之间切换,因为我还需要其他消息,不仅是文件内容。

Therefore, I tried using Protobuf, because it is fast and can serialize/deserialize objects platform independent. 因此,我尝试使用Protobuf,因为它速度快并且可以独立于平台对对象进行序列化/反序列化。 My .proto file is the following: 我的.proto文件如下:

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

So, I set the values for each variable in the generated .java file: 因此,我在生成的.java文件中为每个变量设置值:

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

I saw many tutorials about how to write the objects to a file and read from it. 我看到了许多有关如何将对象写入文件和从文件读取的教程。 However, I can't find any example about how to send a file from server socket to client socket. 但是,我找不到任何有关如何从服务器套接字向客户端套接字发送文件的示例。

My intention is to serialize the object (file size, file name and file content) on the java server and to send these information to the C# client. 我的意图是在Java服务器上序列化对象(文件大小,文件名和文件内容),并将这些信息发送到C#客户端。 So, the file can be deserialized and stored on the client side. 因此,可以反序列化文件并将其存储在客户端。

In my example code above, the server read the bytes of the file (image file) and write it to the output stream, so that the client can read and write the bytes to disk through input stream. 在上面的示例代码中,服务器读取文件(图像文件)的字节并将其写入输出流,以便客户端可以通过输入流将字节读取和写入磁盘。 I want to achieve the same thing with serialization of my generated .proto file. 我想通过对生成的.proto文件进行序列化来实现相同的目的。

Can anyone provide me an example or give me a hint how to do that? 谁能给我一个例子或给我一个提示,怎么做?

As described in the documentation , protobuf does not take care of where a message start and stops, so when using a stream socket like TCP you'll have to do that yourself. 文档中所述,protobuf不会处理消息的开始和停止位置,因此在使用像TCP这样的流套接字时,您必须自己做。

From the doc: 从文档中:

[...] If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins. [...]如果要将多个消息写入单个文件或流,则由您决定一条消息的结束位置和下一条消息的开始位置。 The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own. 协议缓冲区连线格式不是自定界的,因此协议缓冲区解析器无法确定消息在何处结束。 The easiest way to solve this problem is to write the size of each message before you write the message itself. 解决此问题的最简单方法是在编写消息本身之前先编写每个消息的大小。 When you read the messages back in, you read the size, then read the bytes into a separate buffer, then parse from that buffer. 当您读回消息时,您将读取大小,然后将字节读取到单独的缓冲区中,然后从该缓冲区进行解析。 [...] [...]

Length-prefixing is a good candidate. 长度前缀是一个不错的选择。 Depending on what language you're writing, there are libraries that does length-prefixing for eg TCP that you can use, or you can define it yourself. 根据您正在编写的语言,有些库可以为例如TCP使用长度前缀,也可以自己定义。

An example representation of the buffer on the wire might beof the format might be (beginning of buffer to the left): 线路上缓冲区的示例表示形式可能是(格式从左边开始):

[buf_length|serialized_buffer2]

So you code to pack the the buffer before sending might look something like (this is in javascript with node.js): 因此,您在发送之前将代码打包以包装缓冲区可能看起来像(这在带有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;
}

To read you would have to do the opposite: 要阅读,您必须做相反的事情:

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

You should also be aware of that when sending multiple protobufs on a TCP socket, they are likely to be buffered for network optimizations (concatenated) and sent together. 您还应该知道,在TCP套接字上发送多个协议缓冲区时,它们可能会被缓冲以进行网络优化(连接)并一起发送。 Meaning some sort of delimiter is needed anyway. 意味着无论如何都需要某种分隔符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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