序列化消息中的换行符

时间:2019-01-28 07:53:54

标签: protocol-buffers

某些protobuf消息在序列化为字符串时,其内部具有换行符$points = \App\Prize::selectRaw('user_id,COUNT(user_id), date(created_at)') ->groupBy("date(prizes.created_at), user_id") ->orderBy("date(created_at)","DESC") ->having("user_id","=",1) ->get(); 。通常,当消息的第一个字段是字符串时,则在消息之前添加换行符。但是,wa还在中间某处发现了带有换行符的消息。

换行符的问题是当您要将消息逐行保存到一个文件中时。新的换行符使该行中断并使消息无效。

example.proto

\n

example.py

syntax = "proto3";

package data_sources;

message StringFirst {
  string key = 1;
  bool valid = 2;
}

message StringSecond {
  bool valid = 1;
  string key = 2;
}

输出

from protocol_buffers.data_sources.example_pb2 import StringFirst, StringSecond

print(StringFirst(key='some key').SerializeToString())
print(StringSecond(key='some key').SerializeToString())

这是预期/期望的行为吗?如何防止换行符?

1 个答案:

答案 0 :(得分:3)

protobuf是一个二进制协议(除非您在谈论可选的json东西)。因此:无论何时以任何方式将其视为类似于文本的 ,您都在错误地使用它,并且行为是不确定的。这包括担心是否存在CR / LF字符,但也包括诸如nul字符(0x00)之类的东西,在许多框架中,该字符通常被解释为基于文本的API中的字符串结尾(特别是C-字符串)。

特别是:

  • LF(0x0A)与“字段1,长度前缀”的字段标头相同
  • CR(0x0D)与“字段1,固定32位”的字段标头相同
  • 长度前缀(表示长度0、10或13)可能会出现0x00、0x0A或0x0D中的任何一个
  • 二进制数据(bytes)中自然会出现0x00、0x0A或0x0D中的任何一个
  • 任何数字类型都自然会出现0x00、0x0A或0x0D中的任何一个
  • 0x0A或0x0D可能自然出现在文本数据中(如果您的原始框架允许任意字符串中的n个字符,那么0x00也可能如此,所以...不是C字符串)
  • 以及其他可能的范围

所以:再次-如果包含“特殊”文本字符是有问题的:您使用的是错误的

将二进制数据作为文本处理的最常见方法是使用base-N编码。 base-16(hex)便于显示和读取,但是base-64在传达相同字节数所需的字符数方面效率更高。因此,如果可能的话:根据需要转换为base-64。 Base-64永远不会包含任何不可打印的字符,因此您永远不会遇到CR / LF / nul。