草庐IT

java - 通过 Java 解析来自 Go 的协议(protocol)消息

coder 2023-07-01 原文

我写了一个服务器(Go)-客户端(Java)程序,并使用protobuf进行通信。 定义一个 proto 文件并在服务器和客户端之间共享。 在服务器端:

  • 通过protoc将共享proto文件编译成go
  • 通过 proto.Marshal 序列化对象
  • 将其发送给对其服务提出请求的客户

在客户端:

  • 通过protoc将共享proto文件编译成java
  • 获取字节通过http传输
  • 将字节反序列化为对象。

这里我得到以下错误:

"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."

我确认 http 工作正常,客户端接收到的字节值与服务器发送的字节值相同。你有同样的问题吗?

这是原型(prototype)文件

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)

最佳答案

谢谢大家 我从您的所有评论中找到了答案。 我的序列化和反序列化结构不同。 我编辑到 Addressbook.Person person = Addressbook.Person.parseFrom(data); 然后就可以了。

关于java - 通过 Java 解析来自 Go 的协议(protocol)消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45310580/

有关java - 通过 Java 解析来自 Go 的协议(protocol)消息的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  4. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  5. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  6. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  7. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  8. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  9. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  10. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

随机推荐