【发布时间】:2017-07-25 18:01:08
【问题描述】:
我编写了一个服务器(Go)-客户端(Java)程序,并使用 protobuf 进行通信。 定义一个 proto 文件并在服务器和客户端之间共享。 在服务器端:
- 将共享的proto文件编译成go by protoc
- 通过proto.Marshal序列化对象
- 将其发送给对其服务提出请求的客户端
在客户端:
- 通过protoc将共享的proto文件编译成java
- 获取字节通过http传输
- 将字节反序列化为对象。
这里出现以下错误:
“com.google.protobuf.InvalidProtocolBufferException:在解析协议消息时,输入意外在字段中间结束。这可能意味着输入已被截断,或者嵌入的消息误报了自己的长度。”
我确认 http 工作正常,客户端接收到的字节值与服务器发送的字节值相同。你有同样的问题吗?
这是原型文件
syntax = "proto3";
package tutorial;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
在 Go 服务器端:
func TodoIndex(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/x-protobuf")
w.WriteHeader(http.StatusOK)
p := &Person{
Id: 1234,
Name: "John Doe",
Email: "jdoe@example.com",
Phones: []*Person_PhoneNumber{
{Number: "555-4321", Type: Person_HOME},
},
}
out, err := proto.Marshal(p)
if err != nil {
panic(err)
}
w.Write(out)
}
在Java客户端:
public class MainJavaAndGo {
public static void main(String[] args){
try {
long start = (new Date()).getTime();
System.out.println("begin get");
connect();
System.out.println("end get");
long time = (new Date()).getTime() - start;
}catch(Exception e){
e.printStackTrace();
}
}
public static void connect(){
DefaultBHttpClientConnection connection = new DefaultBHttpClientConnection(8 * 1024);
HttpHost server = hostForString("localhost:8080");
try {
Socket socket = new Socket(server.getHostName(), server.getPort());
connection.bind(socket);
HttpCoreContext writeContext = HttpCoreContext.create();
writeContext.setTargetHost(server);
BasicHttpEntityEnclosingRequest httpRequest = new BasicHttpEntityEnclosingRequest("GET",
"/todos");
HttpProcessor httpproc = makeHttpProcessor();
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
httpexecutor.preProcess(httpRequest, httpproc, writeContext);
HttpResponse response = httpexecutor.execute(httpRequest, connection, writeContext);
httpexecutor.postProcess(response, httpproc, writeContext);
InputStream inputStream = response.getEntity().getContent();
byte[] data = IOUtils.toByteArray(inputStream);
Addressbook.AddressBook addressBook = Addressbook.AddressBook.parseFrom(data);
int foo = 0;
foo++;
}catch(Exception e){
e.printStackTrace();
try {
connection.shutdown();
}catch (Exception ioe){
ioe.printStackTrace();
}
}
}
public static HttpHost hostForString(String hostStr) {
String[] host = hostStr.split(":", 2);
HttpHost httphost = new HttpHost(host[0], Integer.parseInt(host[1]));
return httphost;
}
public static HttpProcessor makeHttpProcessor() {
return HttpProcessorBuilder.create().add(new RequestContent()).add(new RequestTargetHost())
.add(new RequestConnControl()).add(new RequestUserAgent("Test Protobuf/1.1"))
.add(new RequestExpectContinue(true)).build();
}
}
我得到了 InvalidProtocolBufferException
com.google.protobuf.InvalidProtocolBufferException: While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.
at com.google.protobuf.InvalidProtocolBufferException.truncatedMessage(InvalidProtocolBufferException.java:82)
at com.google.protobuf.CodedInputStream$ArrayDecoder.skipRawBytes(CodedInputStream.java:1200)
at com.google.protobuf.CodedInputStream$ArrayDecoder.skipField(CodedInputStream.java:578)
at com.auth0.protobuf.Addressbook$Person.<init>(Addressbook.java:112)
at com.auth0.protobuf.Addressbook$Person.<init>(Addressbook.java:77)
at com.auth0.protobuf.Addressbook$Person$1.parsePartialFrom(Addressbook.java:1817)
at com.auth0.protobuf.Addressbook$Person$1.parsePartialFrom(Addressbook.java:1812)
at com.google.protobuf.CodedInputStream$ArrayDecoder.readMessage(CodedInputStream.java:816)
at com.auth0.protobuf.Addressbook$AddressBook.<init>(Addressbook.java:1914)
at com.auth0.protobuf.Addressbook$AddressBook.<init>(Addressbook.java:1871)
at com.auth0.protobuf.Addressbook$AddressBook$1.parsePartialFrom(Addressbook.java:2571)
at com.auth0.protobuf.Addressbook$AddressBook$1.parsePartialFrom(Addressbook.java:2566)
at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:163)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:197)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:209)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:214)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:49)
at com.auth0.protobuf.Addressbook$AddressBook.parseFrom(Addressbook.java:2065)
at com.auth0.MainJavaAndGo.connect(MainJavaAndGo.java:78)
at com.auth0.MainJavaAndGo.main(MainJavaAndGo.java:35)
【问题讨论】:
-
Java 端的套接字是什么样的?听起来您只收到了部分消息。
-
在Java端,我通过HttpRequestExecutor请求服务 HttpHost server = new HttpHost("localhost", 8080); Socket socket = new Socket(server.getHostName(), server.getPort()); connection.bind(socket);
-
你在什么时候从套接字读取?你能用它来编辑你的原始帖子,使其格式正确吗?
-
感谢您的评论。我刚刚发布了完整版的 java 客户端,我通过 httpexecutor.execute 通过 HttpResponse 从服务器获取字节。这就像对宁静服务的请求的响应。
标签: java go protocol-buffers