【发布时间】:2016-03-22 20:12:32
【问题描述】:
我正在尝试将数据从客户端发送到服务器。这两个应用程序都是用java编写的。但是他们使用了一个在 SWIG Wrappers 上用 c++ 实现的 tls 层。 tls 层需要来自客户端的字符串,将其传输到服务器端并通知 java 服务器应用程序(并传递字符串)。但是,此字符串应包含序列化数据。不知何故,我很难使用 protobuf 来序列化数据。我想使用一个名为ToDoListMessage 的java protobuf 类。 protobuf 如下所示:
message ToDoListMessage{
optional string user = 1;
optional string token = 2;
}
但是生成的java类无法解析之前序列化的数据:
com.google.protobuf.InvalidProtocolBufferException:协议消息 标签的电线类型无效。
我目前没有将数据发送到服务器。只是在客户端测试序列化和解析部分:
ToDoListMessageProto msg = ToDoListMessageProto.newBuilder().setUser("test").setToken("38632735722755").build();
byte b [] = msg.toByteArray();
String sMsg = Arrays.toString(b);
System.out.println("send message = " + sMsg);
ToDoListMessageProto outputmessage;
outputmessage = ToDoListMessageProto.parseFrom(sMsg.getBytes());
消息如下:
[10, 4, 116, 101, 115, 116, 18, 14, 51, 56, 54, 51, 50, 55, 51, 53, 55, 50, 50, 55, 53, 53]
我尝试了什么:
1) 到目前为止我发现的所有解决方案都说这个问题可以通过使用CodedOutputStream 来解决。但是 tls 层需要一个字符串,而不是一个流。不过我也尝试过:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CodedOutputStream cos = CodedOutputStream.newInstance(bos);
msg.writeTo(cos);
cos.flush();
byte b [] = msg.toByteArray();
String sMsg = Arrays.toString(b);
但是我在这个解析中得到了与上面相同的错误:
CodedInputStream cis = CodedInputStream.newInstance(sMsg.getBytes());
ToDoListMessageProto message = ToDoListMessageProto.parseFrom(cis);
2) 我也尝试使用 UTF8 编码的字符串而不是类似数组的字符串:
String sMsg = new String(b);
在这种情况下,应用程序的行为更加奇怪。对于短“令牌”(例如小于 129 位),解析有效,但对于长令牌则失败:
com.google.protobuf.InvalidProtocolBufferException:在解析一个 协议消息,输入在中间意外结束 场地。这可能意味着输入已被截断或 嵌入的消息误报了自己的长度。
我真的不知道为什么。目前令牌只包含数字。
有人知道如何从 protobuf 中获取可以正确解析的序列化字符串吗?
再次重申:本次测试不涉及 tls 传输。目前一切都在客户端完成。
更新:
因为我直接从 Protobuf 消息中获取字节数组,所以无法传递编码。我发现该消息还有一个 toByteString 方法,但在此 ByteString 上使用 toStringUtf8 似乎也不起作用:
String sMsg = msg.toByteString().toStringUtf8();
System.out.println("send message = " + sMsg);
ToDoListMessageProto outputmessage;
outputmessage = ToDoListMessageProto.parseFrom(sMsg.getBytes());
我收到相同的错误消息(如果我使用长令牌或短令牌,它们会有所不同,见上文)
【问题讨论】:
-
对于二进制数据,不要使用
String,而仅使用byte[]。由于 String 在内部使用 Unicode,您可以节省编码和解码开销,这也容易出错:不一定总是可能的。 -
事情没那么简单。因为在 c++ 端处理数组会要求内存管理。如果我将这样的数组从 c++ 槽 jni 传递给 java,我将不会简单地知道何时释放内存。这将导致大量额外的编程。
标签: java c++ serialization protocol-buffers