Protocol buffers 如何解码protobuf二进制响应

Protocol buffers 如何解码protobuf二进制响应,protocol-buffers,google-goggles,Protocol Buffers,Google Goggles,我已经创建了一个测试应用程序,可以识别一些图像使用护目镜。它对我有效,但我收到binaryt protobuf响应。我没有原始文件,只有二进制响应。如何从中获取数据?(已经发送了一些关于熊瓶的图片,并得到了nex的回复): 需要获取字符串“Tuborg”,如果可能的话,输入“Logo”我假设真正的问题是如何解码protobufs,而不是如何使用Java从线路中读取二进制文件 你的问题的答案可以找到 简单地说,在网络上,protobuf被编码为的3元组,其中键是分配给.proto模式中字段的字段号

我已经创建了一个测试应用程序,可以识别一些图像使用护目镜。它对我有效,但我收到binaryt protobuf响应。我没有原始文件,只有二进制响应。如何从中获取数据?(已经发送了一些关于熊瓶的图片,并得到了nex的回复):


需要获取字符串“Tuborg”,如果可能的话,输入“Logo”

我假设真正的问题是如何解码protobufs,而不是如何使用Java从线路中读取二进制文件

你的问题的答案可以找到


简单地说,在网络上,protobuf被编码为的3元组,其中键是分配给.proto模式中字段的字段号。这种类型是一种。它只包含足够的信息来解码3元组的值,即它告诉您值的长度。

您可以使用
protoc
进行解码:

protoc --decode_raw < msg.bin
protoc--decode_raw
这将显示顶级字段。不幸的是,它无法知道字段类型的确切细节。long/int/bool/enum等都编码为Varint,看起来都一样。字符串、字节数组和子消息是以长度分隔的,并且不可区分

以下是一些有用的细节:

如果您按照UnknownFieldSet.mergeFrom()中的代码进行操作,您将看到如何尝试解码子消息,如果解码失败,则返回到字符串,但这不是很可靠

协议中的wiretype有两个备用值——如果google使用其中一个来表示子消息,这将非常有用。(另一个可能是空值。)

下面是一些非常粗糙的代码,它试图生成一个对诊断有用的东西。它猜测数据类型,在字符串和子消息的情况下,在某些情况下,它将打印这两种备选方案。请不要相信它打印的任何值:

public static String decodeProto(byte[] data, boolean singleLine) throws IOException {
    return decodeProto(ByteString.copyFrom(data), 0, singleLine);
}

public static String decodeProto(ByteString data, int depth, boolean singleLine) throws IOException {
    final CodedInputStream input = CodedInputStream.newInstance(data.asReadOnlyByteBuffer());
    return decodeProtoInput(input, depth, singleLine);
}

private static String decodeProtoInput(CodedInputStream input, int depth, boolean singleLine) throws IOException {
    StringBuilder s = new StringBuilder("{ ");
    boolean foundFields = false;
    while (true) {
        final int tag = input.readTag();
        int type = WireFormat.getTagWireType(tag);
        if (tag == 0 || type == WireFormat.WIRETYPE_END_GROUP) {
            break;
        }
        foundFields = true;
        protoNewline(depth, s, singleLine);

        final int number = WireFormat.getTagFieldNumber(tag);
        s.append(number).append(": ");

        switch (type) {
            case WireFormat.WIRETYPE_VARINT:
                s.append(input.readInt64());
                break;
            case WireFormat.WIRETYPE_FIXED64:
                s.append(Double.longBitsToDouble(input.readFixed64()));
                break;
            case WireFormat.WIRETYPE_LENGTH_DELIMITED:
                ByteString data = input.readBytes();
                try {
                    String submessage = decodeProto(data, depth + 1, singleLine);
                    if (data.size() < 30) {
                        boolean probablyString = true;
                        String str = new String(data.toByteArray(), Charsets.UTF_8);
                        for (char c : str.toCharArray()) {
                            if (c < '\n') {
                                probablyString = false;
                                break;
                            }
                        }
                        if (probablyString) {
                            s.append("\"").append(str).append("\" ");
                        }
                    }
                    s.append(submessage);
                } catch (IOException e) {
                    s.append('"').append(new String(data.toByteArray())).append('"');
                }
            break;
            case WireFormat.WIRETYPE_START_GROUP:
                s.append(decodeProtoInput(input, depth + 1, singleLine));
                break;
            case WireFormat.WIRETYPE_FIXED32:
                s.append(Float.intBitsToFloat(input.readFixed32()));
                break;
            default:
                throw new InvalidProtocolBufferException("Invalid wire type");
        }

    }
    if (foundFields) {
        protoNewline(depth - 1, s, singleLine);
    }
    return s.append('}').toString();
}

private static void protoNewline(int depth, StringBuilder s, boolean noNewline) {
    if (noNewline) {
        s.append(" ");
        return;
    }
    s.append('\n');
    for (int i = 0; i <= depth; i++) {
        s.append(INDENT);
    }
}
publicstaticstringdecodeproto(byte[]数据,布尔单行)抛出IOException{
返回decodeProto(ByteString.copyFrom(数据),0,单线);
}
公共静态字符串解码协议(ByteString数据、int深度、布尔单线)引发IOException{
final CodedInputStream input=CodedInputStream.newInstance(data.asReadOnlyByteBuffer());
返回输入(输入、深度、单线);
}
私有静态字符串decodeProtoInput(CodedInputStream输入、int深度、布尔单线)引发IOException{
StringBuilder s=新的StringBuilder(“{”);
布尔foundFields=false;
while(true){
final int tag=input.readTag();
int type=WireFormat.getTagWireType(标记);
if(标记==0 | |类型==WireFormat.WIRETYPE_END_GROUP){
打破
}
foundFields=true;
原型换行符(深度、s、单线);
最终整数=WireFormat.getTagFieldNumber(标记);
s、 追加(数字)。追加(“:”);
开关(类型){
case WireFormat.WIRETYPE\u变量:
s、 追加(input.readInt64());
打破
案例WireFormat.WIRETYPE\u FIXED64:
s、 append(Double.longBitsToDouble(input.readFixed64());
打破
大小写WireFormat.WIRETYPE\u长度\u分隔:
ByteString data=input.readBytes();
试一试{
字符串子消息=解码协议(数据,深度+1,单线);
if(data.size()<30){
布尔概率字符串=真;
String str=新字符串(data.toByteArray(),Charsets.UTF_8);
for(字符c:str.toCharArray()){
如果(c<'\n'){
probablyString=false;
打破
}
}
如果(可能是字符串){
s、 追加(\).append(str.append(\);
}
}
s、 附加(子消息);
}捕获(IOE异常){
s、 append(“”).append(新字符串(data.toByteArray()).append(“”);
}
打破
案例WireFormat.WIRETYPE\u开始\u组:
s、 追加(解码输入(输入,深度+1,单线));
打破
案例WireFormat.WIRETYPE\u FIXED32:
s、 追加(Float.intBitsToFloat(input.readFixed32());
打破
违约:
抛出新的InvalidProtocolBufferException(“无效导线类型”);
}
}
if(foundFields){
原型新线(深度-1,s,单线);
}
返回s.append('}').toString();
}
私有静态void协议换行符(int-depth、StringBuilder s、布尔非换行符){
if(非WLINE){
s、 附加(“”);
返回;
}
s、 追加('\n');

对于(int i=0;i)您可以使用什么语言?大多数实现中都有解码流读取器。但是,我担心这些数据是如何编码的。您是否有实际的
字节[]
数据?(我问了一个问题,因为这看起来像是编码糟糕的(即损坏的)数据)不,数据没有问题。我已将响应读取为byte[]数组,它只是此数据的字符串表示形式。下面是对具有Steve Jobs名称的图像的另一个响应:Z Steve Jobs Text#Manifesto da Morto相似图像???;?~Ui4{C~27e437b3469557e98“?+TR=T=2NKSRNijdzY:X=Op9HS:S=q5e2gggtn2fhbxr+TR=T=-hAbOrM2yME:X=Op9HS:S=XJ0SUV2EWG1A2Z7O+TR=T=4fEn46Y2 xM:X=Op9HS:S=xIk9lP93EkhBQroz+TR=T=-s6bJFuLuRo:X=Op9HS:S=cpnqt361zynv+TR=T=T=T=2hSkrpEoO10:X=xuv9hs:jsqh1s=jsh5h9wms表示法”这个字符串仅表示“数据”这里可能有意义的是:base-64或十六进制编码。看起来您是通过UTF-8或其他方式运行的,这是无效的,并且会丢失数据。另外,我重复一下:您有什么语言可以使用?我使用的是JAVA,这是链接t
UnknownFieldSet.parseFrom(msg).toString()
public static String decodeProto(byte[] data, boolean singleLine) throws IOException {
    return decodeProto(ByteString.copyFrom(data), 0, singleLine);
}

public static String decodeProto(ByteString data, int depth, boolean singleLine) throws IOException {
    final CodedInputStream input = CodedInputStream.newInstance(data.asReadOnlyByteBuffer());
    return decodeProtoInput(input, depth, singleLine);
}

private static String decodeProtoInput(CodedInputStream input, int depth, boolean singleLine) throws IOException {
    StringBuilder s = new StringBuilder("{ ");
    boolean foundFields = false;
    while (true) {
        final int tag = input.readTag();
        int type = WireFormat.getTagWireType(tag);
        if (tag == 0 || type == WireFormat.WIRETYPE_END_GROUP) {
            break;
        }
        foundFields = true;
        protoNewline(depth, s, singleLine);

        final int number = WireFormat.getTagFieldNumber(tag);
        s.append(number).append(": ");

        switch (type) {
            case WireFormat.WIRETYPE_VARINT:
                s.append(input.readInt64());
                break;
            case WireFormat.WIRETYPE_FIXED64:
                s.append(Double.longBitsToDouble(input.readFixed64()));
                break;
            case WireFormat.WIRETYPE_LENGTH_DELIMITED:
                ByteString data = input.readBytes();
                try {
                    String submessage = decodeProto(data, depth + 1, singleLine);
                    if (data.size() < 30) {
                        boolean probablyString = true;
                        String str = new String(data.toByteArray(), Charsets.UTF_8);
                        for (char c : str.toCharArray()) {
                            if (c < '\n') {
                                probablyString = false;
                                break;
                            }
                        }
                        if (probablyString) {
                            s.append("\"").append(str).append("\" ");
                        }
                    }
                    s.append(submessage);
                } catch (IOException e) {
                    s.append('"').append(new String(data.toByteArray())).append('"');
                }
            break;
            case WireFormat.WIRETYPE_START_GROUP:
                s.append(decodeProtoInput(input, depth + 1, singleLine));
                break;
            case WireFormat.WIRETYPE_FIXED32:
                s.append(Float.intBitsToFloat(input.readFixed32()));
                break;
            default:
                throw new InvalidProtocolBufferException("Invalid wire type");
        }

    }
    if (foundFields) {
        protoNewline(depth - 1, s, singleLine);
    }
    return s.append('}').toString();
}

private static void protoNewline(int depth, StringBuilder s, boolean noNewline) {
    if (noNewline) {
        s.append(" ");
        return;
    }
    s.append('\n');
    for (int i = 0; i <= depth; i++) {
        s.append(INDENT);
    }
}