java - 损坏的 Protocol Buffer 消息

标签 java swift protocol-buffers gcdasyncsocket

我正在使用Protocol Buffers for Swift (最新来自 CocoaPods)和 Google 的官方 Java Protocol buffer 客户端(版本 2.6.0),用于在 Java 服务器 (ServerSocket) 和 Swift iOS 应用程序 (GCDAsyncSocket) 之间传递消息。

大多数消息(每秒数百条;我将音频作为 float 组等进行流式传输)都运行良好。然而,有时,从客户端到服务器的消息将无法解析。 Java 代码抛出

com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero)

在两端,我发送一个 4 字节的 Big-Endian 整数,表示要跟随的字节数,然后发送原始 protobuf 消息。在两端,我都接收要跟随的字节数,阻塞直到获得那么多字节,然后尝试解析。

在 Java->Swift 方向没有观察到错误,只有 Swift->Java。

绝大多数消息都很好。随着处理的消息数量的增加,该问题的出现频率似乎也会增加。

在 Java 中,每个客户端都有一个与之通信的线程和一个监听它的线程。监听器线程从线路中拉出消息并将其放入每个客户端的 LinkedBlockingQueues 中。对话线程从该客户端的 LinkedBlockingQueue 中提取消息,序列化它们,然后将它们发送到该客户端的输出流。

// Take a messageBuilder, serialize and transmit it
func transmit(messageBuilder: Message_.Builder) {
    do {
        messageBuilder.src = self.networkID;
        let data = try messageBuilder.build().data()
        var dataLength = CFSwapInt32HostToBig(UInt32(data.length))

        self.socket.writeData(NSData(bytes: &dataLength, length: 4), withTimeout: 1, tag: 0)
        self.socket.writeData(data, withTimeout: 1, tag: 0)
    } catch let error as NSError {
        NSLog("Failed to transmit.")
        NSLog(error.localizedDescription)
    }
}

Java接收端:

        public void run() {
        while (true) {
            try {
                byte[] lengthField = new byte[4];
                try {
                    ghost.in.readFully(lengthField, 0, 4);
                } catch (EOFException e) {
                    e.printStackTrace();
                    ghost.shutdown();
                    return;
                }
                Integer bytesToRead = ByteBuffer.wrap(lengthField).order(ByteOrder.BIG_ENDIAN).getInt();
                byte[] wireMessage = new byte[bytesToRead];
                in.readFully(wireMessage, 0, bytesToRead);

                HauntMessaging.Message message = HauntMessaging.Message.parseFrom(wireMessage);

                // do something with the message


            } catch (IOException e) {
                e.printStackTrace();
                ghost.shutdown();
                return;
            }
        }
    }

有什么想法吗?

最佳答案

调试 Protocol Buffer 消息:

  1. 在Wireshark中抓包

  2. 右键单击仅包含 protobuf 消息的数据包部分并复制十六进制流

  3. 使用十六进制编辑器将十六进制流保存到文件

  4. protoc ‒‒decode_raw < file并将输出标签和数据与 .proto 文件中的标签相匹配

由于异常消息,Protocol message contained an invalid tag (zero) ,我怀疑Swift未能构建protobuf消息并发送了一条空消息。

关于java - 损坏的 Protocol Buffer 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35974703/

相关文章:

java - 使用 Java (Spring) 从数据库安排任务的最佳方式

c# - protobuf-net 和 rpc over tcp

c# - 如何使用 protobuf-net 读取 fixed32 整数?

java - mongo中的原子读取和删除

java - Eclipse - 如何将快捷键命令分配给启动类型(运行方式类型)

ios - 如何在 UITableViewCell 中创建未知数量的 UILabels?

ios - 在同一个表上使用 2 个 NSFetchedResultsController 时出现 CoreData 严重错误

swift - 根据保持纵横比 [Swift] 的屏幕尺寸调整 CollectionView 中项目布局的大小

spring - 在 Camel Marshal 和 Unmarshal 标签中使用 Spring 表达式语言

java - 获取哪个Jframe打开了另一个Jframe