将协议缓冲区编码的消息从 Python 服务器发送到 Java 客户端
Sending Protocol Buffer encoded message from Python Server to Java Client
我正在编写一个使用协议缓冲区对一些数据进行编码的小型服务器。
TCP 套接字在 Android 客户端和 Python 服务器之间打开
Android 客户端发送字符串作为普通换行符分隔的 utf-8 进行处理。
Python 服务器进行一些处理以生成响应,该响应给出 Int 数组的数组:[[int]]。这是在协议缓冲区文件中编码的:
syntax = "proto2";
package tts;
message SentenceContainer {
repeated Sentence sentence = 1;
}
message Sentence {
repeated uint32 phonemeSymbol = 1;
}
它被加载到这个结构中并按如下方式发送...
container = ttsSentences_pb2.SentenceContainer()
for sentence in input_sentences:
phonemes = container.sentence.add()
# Add all the phonemes to the phoneme list
phonemes.phonemeSymbol.extend(processor.text_to_sequence(sentence))
payload = container.SerializeToString()
client.send(payload)
- Android 客户端收到 Protocol Buffer 编码的消息并尝试解码。
这就是我卡住的地方...
# I get the InputStream when the TCP connection is first opened
bufferIn = socket.getInputStream();
TtsSentences.SentenceContainer sentences = TtsSentences.SentenceContainer.parseDelimitedFrom(bufferIn);
客户端收到消息时出现此异常:
E/TCP: Server Error
com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.
at com.google.protobuf.CodedInputStream.checkLastTagWas(CodedInputStream.java:164)
at com.google.protobuf.GeneratedMessageLite.parsePartialDelimitedFrom(GeneratedMessageLite.java:1527)
at com.google.protobuf.GeneratedMessageLite.parseDelimitedFrom(GeneratedMessageLite.java:1496)
at com.tensorspeech.tensorflowtts.TtsSentences$SentenceContainer.parseDelimitedFrom(TtsSentences.java:221)
at com.tensorspeech.tensorflowtts.network.PersistentTcpClient.run(PersistentTcpClient.java:100)
at com.tensorspeech.tensorflowtts.MainActivity.lambda$onCreate[=15=]$MainActivity(MainActivity.java:71)
at com.tensorspeech.tensorflowtts.-$$Lambda$MainActivity$NTUE8bAusaoF3UGkWb7-Jt806BY.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:919)
我已经知道这个问题是因为 Protocol buffer 不是自定界的,但我不确定我应该如何正确地定界它。我已经尝试添加一个换行符 client.send(payload + b'\n')
,并在有效负载的开头添加以字节为单位的 PB 大小 client.send(container.ByteSize().to_bytes(2, 'little') + payload)
,但我不确定如何继续。
遗憾的是,在 Java...
中没有关于如何通过 TCP 套接字使用 Protocol Buffer 的文档
好的,我解决了...
在您有 short-lived 连接的情况下,套接字关闭将表示有效负载结束,因此不需要额外的逻辑。
在我的例子中,我有一个 long-lived 连接,因此关闭套接字以表示有效负载结束是行不通的。
使用 Java 客户端和服务器,您可以使用以下方法解决此问题:
MessageLite.writeDelimitedTo(OutputStream)
然后在收件人方面:
MessageLite.parseDelimitedFrom(InputStream)
.
很简单...
但是在PythonAPI中没有writeDelimitedTo()
功能。因此,我们必须重新创建 writeDelimitedTo()
正在做的事情。幸运的是,这很简单。它只是在消息的开头添加一个等于有效负载大小的 _VarintBytes!
client, _ = socket.accept()
payload = your_PB_item.SerializeToString()
size = payload.ByteSize()
client.send(_VarintBytes(size) + payload)
然后在 Java 接收方...
bufferIn = socket.getInputStream();
yourPbItem message;
if ((message = yourPbItem.parseDelimitedFrom(bufferIn)) != null) {
// Do stuff :)
}
这样,您的协议缓冲区库就知道要读取多少字节,然后停止关心 InputStream,而不是无限期地坐着听。
我正在编写一个使用协议缓冲区对一些数据进行编码的小型服务器。
TCP 套接字在 Android 客户端和 Python 服务器之间打开
Android 客户端发送字符串作为普通换行符分隔的 utf-8 进行处理。
Python 服务器进行一些处理以生成响应,该响应给出 Int 数组的数组:[[int]]。这是在协议缓冲区文件中编码的:
syntax = "proto2";
package tts;
message SentenceContainer {
repeated Sentence sentence = 1;
}
message Sentence {
repeated uint32 phonemeSymbol = 1;
}
它被加载到这个结构中并按如下方式发送...
container = ttsSentences_pb2.SentenceContainer()
for sentence in input_sentences:
phonemes = container.sentence.add()
# Add all the phonemes to the phoneme list
phonemes.phonemeSymbol.extend(processor.text_to_sequence(sentence))
payload = container.SerializeToString()
client.send(payload)
- Android 客户端收到 Protocol Buffer 编码的消息并尝试解码。
这就是我卡住的地方...
# I get the InputStream when the TCP connection is first opened
bufferIn = socket.getInputStream();
TtsSentences.SentenceContainer sentences = TtsSentences.SentenceContainer.parseDelimitedFrom(bufferIn);
客户端收到消息时出现此异常:
E/TCP: Server Error
com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.
at com.google.protobuf.CodedInputStream.checkLastTagWas(CodedInputStream.java:164)
at com.google.protobuf.GeneratedMessageLite.parsePartialDelimitedFrom(GeneratedMessageLite.java:1527)
at com.google.protobuf.GeneratedMessageLite.parseDelimitedFrom(GeneratedMessageLite.java:1496)
at com.tensorspeech.tensorflowtts.TtsSentences$SentenceContainer.parseDelimitedFrom(TtsSentences.java:221)
at com.tensorspeech.tensorflowtts.network.PersistentTcpClient.run(PersistentTcpClient.java:100)
at com.tensorspeech.tensorflowtts.MainActivity.lambda$onCreate[=15=]$MainActivity(MainActivity.java:71)
at com.tensorspeech.tensorflowtts.-$$Lambda$MainActivity$NTUE8bAusaoF3UGkWb7-Jt806BY.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:919)
我已经知道这个问题是因为 Protocol buffer 不是自定界的,但我不确定我应该如何正确地定界它。我已经尝试添加一个换行符 client.send(payload + b'\n')
,并在有效负载的开头添加以字节为单位的 PB 大小 client.send(container.ByteSize().to_bytes(2, 'little') + payload)
,但我不确定如何继续。
遗憾的是,在 Java...
中没有关于如何通过 TCP 套接字使用 Protocol Buffer 的文档好的,我解决了...
在您有 short-lived 连接的情况下,套接字关闭将表示有效负载结束,因此不需要额外的逻辑。
在我的例子中,我有一个 long-lived 连接,因此关闭套接字以表示有效负载结束是行不通的。
使用 Java 客户端和服务器,您可以使用以下方法解决此问题:
MessageLite.writeDelimitedTo(OutputStream)
然后在收件人方面:
MessageLite.parseDelimitedFrom(InputStream)
.
很简单...
但是在PythonAPI中没有writeDelimitedTo()
功能。因此,我们必须重新创建 writeDelimitedTo()
正在做的事情。幸运的是,这很简单。它只是在消息的开头添加一个等于有效负载大小的 _VarintBytes!
client, _ = socket.accept()
payload = your_PB_item.SerializeToString()
size = payload.ByteSize()
client.send(_VarintBytes(size) + payload)
然后在 Java 接收方...
bufferIn = socket.getInputStream();
yourPbItem message;
if ((message = yourPbItem.parseDelimitedFrom(bufferIn)) != null) {
// Do stuff :)
}
这样,您的协议缓冲区库就知道要读取多少字节,然后停止关心 InputStream,而不是无限期地坐着听。