简介
什么是 Google Protocol Buffer? 假如您在网上搜索,应该会得到类似这样的文字介绍:
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
protobuf协议基础
介绍主题
l Protocol Buffers简介
l 定义一个.proto文件
l Message的使用
l 消息的编码机制
l 使用时注意事项
什么是ProtocolBuffers?
l Google定义的一种序列化的协议格式;
l Google内部几乎所有的RPC调用及文件格式;
(据称当前google已经定义了12,183个.proto文件,共有48,162种不同的message类型。它们用于RPC系统或各种存储系统中进行数据的存储)
l 目标:
Ø 简单性
Ø 兼容性
Ø 高性能
XML与Protobuf的比较
易读性 二进制格式;
自描述语言 没有.proto文件根据就是无用的;
文件大 文件小(3-10倍);
解析及序列化较慢快(20- 100倍);
.xsd(复杂).proto(简单,无二义性);
访问简单访问容易;
message示例
从.proto文件到运行时
在.proto文件中定义消息;
用protoc编译器将其编译成源代码
Ø C++
Ø Java
Ø Python
在代码中直接使用接口
通过网络进行传输或存储
Message的定义
SAP通过Message来回执程序的执行状态。使用Tcode:SE91.
SAP將Message分为不同的类,如下图显示为ZF环境下ZMM01类相关Message列表。
Message short text字段为类描叙,也可以定义输入参数&,如&1&2&3表示有三个输入参数。
Message共分以下几种类型:E——错误;W——警告;I——信息;A——异常中止;S——成功。
定义语法为:MessageW000(mid), mid表示为类名,
例如: Message W000(00),表示调用ZMM01类的000Message类型为警告。也可以在程序开头直接引用Message-ID,如:
REPORT Y001 MESSAGE-ID ZMM01.
MESSAGE W002.
REPORT Y001.
MESSAGE W002(ZMM01).
以上两种执行效果都是一样的,第一个是程序一开始就应用该消息类,第二个是程序执行中才引用消息类。
REPORT Y001 MESSAGE-ID 00.
DATA:MSG1(10) TYPE C VALUE 'this'.
DATA:MSG2(10) TYPE C VALUE ' is'.
DATA:MSG3(10) TYPE C VALUE ' my'.
DATA:MSG4(10) TYPE C VALUE ' test.'.
MESSAGE W001 WITH MSG1 MSG2 MSG3 MSG4.
E、W、S类型Message一般会在状态栏显示,但I类型则会弹出对话框,
A类型在弹出对话框的周时将强制退出执行程序。
REPORT Y001 MESSAGE-ID 00.
SELECTION-SCREEN BEGIN OF BLOCK MYBLOCK WITH FRAME.
PARAMETERS:P_LENGTH TYPE I LENGTH 5 ," VISIBLE LENGTH 5
P_WIDTH TYPE I VISIBLE LENGTH 5.
SELECTION-SCREEN END OF BLOCK MYBLOCK.
IF P_LENGTH IS NOT INITIAL. "如果不為空
DATA AREA TYPE I.
AREA = P_LENGTH * P_WIDTH.
MESSAGE I003(00) WITH P_LENGTH P_WIDTH AREA. "调用自定义MESSAGE
ENDIF.
Required是必须的
在用required修饰符时一定要谨慎;
一旦域被required修饰,该值就必须要进行传递,在版本升级或兼容时可能存在问题;
Googe工程师不建议使用required修饰符;
域id(标识)
每个域都有唯一的标识(id) (1-2^29)
注:不可以使用其中的[19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。
变量采用的是可变长的编码方式
[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。应该为那些频繁出现的消息元素保留[1,15]之内的标识号。
在二进制格式的数据中唯一标识该域
域的名字在数据编码时不会使用到,编码中完全采用id来进行域的标识。
选项,命名空间及消息导入
Options:
[default = value] -> 为该域设置一个默认值 (默认值是不需编码的)
如:optional uint32 ad_bid_count = 4[default = 2];
[packed =false / true]->采用更紧凑的编码方式
如:repeated int32 samples = 4[packed=true];
[deprecated =false/true]->标识该域是否已经被弃用
如:optional int32 old_field = 6[deprecated=true];
[optimize_for= SPEED/CODE/LITE_RUNTIME]:影响代码生成
Package:
命名空间,影响java的包名及生成的类名;
如:packagecom.example.message
Import:
导入其它文件中的message
如:import “myfile/message1.proto”
Message的使用
Variants:
1. MESSAGE xnnn.
2. MESSAGE ID id TYPE mtype NUMBER n.
3. MESSAGE xnnn(mid).
4. MESSAGE msg TYPE mtype.
Effect
Sends a message. Messages are stored in the table T100, are processed using transaction SE91 and can be created by forward navigation.
The ABAP runtime environment handles messages according to the type declared in the MESSAGE statement and the context in which the message was sent. The following message types exist:
A - Abend : Transaction terminated E - Error : Error message I - Info : Information S - Status : Status message W - Warning : Correction possible X - Exit : Transaction terminated with short dump
Messages are mainly used to handle user input on screens. The following table shows the behavior of each message type in each context. An explanation of the numbers used is included at the end of the table:
A E I S W X
--------------------------------------------------------------
PAI Module 1 2 3 4 5 6
PAI Module for POH 1 7 3 4 7
6
PAI Module for POV 1 7 3 4 7
6
--------------------------------------------------------------
AT SELECTION-SCREEN ... 1 8 3 4 9 6
AT SELECTION-SCREEN for POH 1 7 3 4 7 6
AT SELECTION-SCREEN for POV 1 7 3 4 7 6
AT SELECTION-SCREEN ON EXIT 1 7 3 4 7 6
--------------------------------------------------------------
AT LINE-SELECTION 1 10 3 4 10 6
AT PFn 1 10 3 4 10 6
AT USER-COMMAND 1 10 3 4 10 6
--------------------------------------------------------------
INITIALIZATION 1 11 3 4 11 6
START-OF-SELECTION 1 11 3 4 11 6
GET 1 11 3 4 11 6
END-OF-SELECTION 1 11 3 4 11 6
--------------------------------------------------------------
TOP-OF-PAGE 1 11 3 4 11 6
END-OF-PAGE 1 11 3 4 11 6
TOP-OF-PAGE DURING ... 1 10 3 4 10 6
--------------------------------------------------------------
LOAD-OF-PROGRAM 1 1 4 4 4 6
--------------------------------------------------------------
PBO Module 1 1 4 4 4 6
AT SELECTION-SCREEN OUTPUT 1 1 4 4 4 6
--------------------------------------------------------------
Procedure: see
Messages
--------------------------------------------------------------
- The message appears in a dialog box and the program terminates. When the user has confirmed the message, control returns to the next- highest area. All the internal sessions are deleted from the stack.
- The message appears in the status line. Then PAI terminates and the system returns to the current screen. All the screen fields combined using FIELD or CHAIN are now ready for input. The user must enter new values. The system triggers the PAI event again, with the new values.
- The message appears in a dialog box. Once the user has confirmed the message, the program continues immediately after the MESSAGE statement.
- The message appears in the status line of the next screen. The program continues immediately after the message statement.
- The message appears in the status line. Then the system continues as in 2, except that the user can quit the message using ENTER without having to enter new values. The system continues handling the PAI event from immediately after the message statement.
- No message is displayed and a runtime error, MESSAGE_TYPE_X, is triggered. The short dump text contains the message identification.
- The program terminates with a runtime error DYNPRO_MSG_IN_HELP. While F1 and F4 are processed, the system cannot send error messages or warnings.
- The message appears in the status line. Then the system stops selection screen processing and returns to the selection screen itself. The screen fields specified in the additions to the AT SELECTION-SCREEN statement are now ready for input. The user must enter new values. The system then starts processing the selection screen again with the new values.
- The message appears in the status line. Then the system continues as in 8, except the the user can quit the message using ENTER, without having to enter new values. The system continues handling the PAI event from immediately after the message statement.
- The message appears in the status line and the processing block terminates. The list level is displayed as before.
- The message appears in the status line and the processing block terminates. The system then returns to the program call.
- For a demonstration of messages in different contexts, see Example Programs for Messages.
Variant 1
MESSAGE xnnn.
Extras:
1. ... WITH f1 ... f4
2. ... RAISING exception
3. ... INTO f
4. ... DISPLAY LIKE mtype
Effect
Outputs the message nnn from the message class i with the type x. You must specify the message class i using the MESSAGE-IDaddition to the REPORT statement, PROGRAM, or another introductory program statement.
Example
MESSAGE I001.
- You can specify a different message class in parentheses after the error number, for example MESSAGE I001(SU).
- When executing the statement, the following system variables are set:
- * SY-MSGID (message class)
- * SY-MSGTY (message type)
- * SY-MSGNO (message number)
Addition 1
... WITH f1 ... f4
Effect
Inserts the contents of a field fi in the message instead of in the placeholder &i. If unnumbered variables (&) are used in a message text, these are replaced consecutively by the fields f1 to f4.
To aid compilation, only numbered variables (&1 to &4) are to be used in future if several fields are involved.
If a "&" is supposed to appear in the message at runtime, you must enter &&.
In the long text of a message, the symbol &Vi& is replaced by the field contents of fi.
After WITH, you can specify 1 to 4 fields.
Note
You can output up to 50 characters per field. If the field contains more characters, these are ignored.
Example
MESSAGE E0004 WITH 'Hugo'.
Note
When executing the statement, the contents of the fields f1 to f4 are assigned to the system fields SY-MSGV1, SY-MSGV2, SY-MSGV3and SY-MSGV4.
Addition 2
... RAISING exception
Effect
Only possible within a function module or a method (see FUNCTION, METHOD):
Triggers the exception exception.
If the program calling the function module or method handles the exception itself, control returns immediately to that program (see CALL FUNCTION and CALL METHOD). Only then are the current values passed from the procedure to the EXPORTING-, CHANGING- (und RETURNING) parameters of the function module or method, if they are specified as pass-by- reference. However, the calling program can refer to the system field values (see above).
If the calling program does not handle the exception itself, the message is output (see RAISE).
You cannot use this addition in conjunction with the ... INTO cf addition.
Note
If, during a Remote Function Call, an error occurs in the target system, details of the error message are passed back to the calling system in the following system fields: SY-MSGNO, SY-MSGID, SY-MSGTY, SY-MSGV1, SY-MSGV2, SY-MSGV3, and SY-MSGV4. These fields are initialized before every RFC. If a short dump or a type X message occurs, the short text of the dump is transferred to the caller, and the contents of SY-MSGID, SY-MSGTY, SY-MSGNO, and SY-MSGV1 assigned by the system.
In RFC-enabled function modules, no ABAP statements are allowed that would end the RFC connection (for example, either LEAVE or SUBMIT without the AND RETURN addition).
Example
MESSAGE E001 RAISING NOT_FOUND.
Addition 3
... INTO f
Effect
Instead of displaying the message, the system places the message text in the field f. The message type is not evaluated.
You cannot use this addition in conjunction with the ...RAISING exception or the DISPLAY LIKE mtype addition. The system sets the following system variables: SY-MSGID (message class), SY-MSGTY (message type), SY-MSGNO (message number) and SY-MSGV1, SY-MSGV2, SY-MSGV3, SY-MSGV4 (parameters).
Example
DATA msgtext(72).
...
MESSAGE E004 WITH 'Hugo' INTO msgtext.
Addition 4
... DISPLAY LIKE mtype
Effect
The message display uses the icon of the message type mtype but the message is handled according to its actual type.
Note
This addition cannot be used in conjunction with the addition ... INTO.
Example
MESSAGE I004 DISPLAY LIKE 'E'.
Variant 2
MESSAGE ID id TYPE mtype NUMBER n.
Extras:
1. ... WITH f1 ... f4
2. ... RAISING exception
3. ... INTO f
4. ... DISPLAY LIKE mtype
Effect
The message components are set dynamically:
ID Message class TYPE Message type NUMBER Message number
The addition MESSAGE-ID of the introductory program statement is not required or is overridden.
Addition 1
... WITH f1 ... f4
Addition 2
... RAISING exception
Addition 3
... INTO f
Addition 4
... DISPLAY LIKE mtype
Effect
As in variant 1.
Example
MESSAGE ID 'SU' TYPE 'E' NUMBER '004' WITH 'Hugo'.
Outputs the message with the number 004 and MESSAGE-ID SU (see above) as an E (Error) message and replaces the first variable (&) with 'Hugo'.
Example
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
Constructs the message dynamically from the contents of the system fields SY-MSGID, SY-MSGTY, SY-MSGNR , SY-MSGV1 ,SY-MSGV2,SY-MSGV3,and SY-MSGV4. These may, for example, be set by an exception after CALL FUNCTION or CALL TRANSACTION ... USING.
Variant 3
MESSAGE xnnn(mid).
Extras:
1. ... WITH f1 ... f4
2. ... RAISING exception
3. ... INTO f
4. ... DISPLAY LIKE mtype
Effect
As in variant 1. The message class is determined by specifying mid. The addition MESSAGE-ID of the introductory program statement is not required or is overridden.
Addition 1
... WITH f1 ... f4
Addition 2
... RAISING exception
Addition 3
... INTO f
Addition 4
... DISPLAY LIKE mtype
Effect
As in variant 1.
Example
MESSAGE X004(SU) WITH 'Hugo'.
Variant 4
MESSAGE msg TYPE mtype.
Extras:
1. ... RAISING exception
2. ... DISPLAY LIKE mtype
Effect
With this variant, the message can be passed directly in the form of a character-like field. The message type is specified using the required TYPE addition.
Addition 1
... RAISING exception
Addition 2
... DISPLAY LIKE mtype
Effect
As in variant 1.
Example
MESSAGE 'File not found.' TYPE 'E'.
The text 'File not found.' is output as the error message.
Exceptions
Non-Catchable Exceptions
- Cause: Message type unknown
- Runtime Error: MESSAGE_TYPE_UNKNOWN
- Cause: Triggers termination with a short dump
- Runtime Error: MESSAGE_TYPE_X
Additional help
Messages
为消息设置具体的值
序列化及解析数据
序列化:
获取消息的具体值
消息编码机制
l 一个简单的消息编码;
l 基于128的Varints;
l 消息结构
l 其它值类型
一个简单的消息编码
消息格式定义如下:
在一个应用程序中,创建了一个Test1消息,并将其中的a设置为150。序列化该消息将可以看到3个字节。
0896 01
如何将该消息序列化为该格式呢?
基于128的Varints
Varints是一种将整数采用1个或多个字节序列的方法。越小的数据需要采用更少的字节。
每个Byte的最高位(msb)是标志位,如果该位为1,表示该Byte后面还有其它Byte,如果该位为0,表示该Byte是最后一个Byte。每个Byte的低7位是用来存数值的位。
Varints方法用Litte-Endian(小端)字节序。
示例:
1:0000 0001
300:1010 1100 0000 0010
消息的结构
每条消息(message)都是由一系列的key-value对组成的。
key由两部分组成,一部分是在定义消息时字段的编号(field_num),另一部分是字段的类型(wire_type)。
对于流消息中的每个key值,也是采用varint方式来表示其值的,计算格式如下(field_number
protoBuf使用实战
在Android studio中配置使用protobuf,网上有很多资料,但几乎找不到与后台交互,
拿到数据后怎么进行反序列化的操作,下面记录下:
首先定义 .proto文件,我们跟后台交互是有请求头和请求体的。
下面是使用socket进行通讯的类
//最终结果
byte[] lastResult = tempISO.getBytes(Charset.forName("ISO-8859-1"));
//先解body,这是重点,必须要先把body解出来。用后台返回的字节数据进行解析
MsgBodyOuterClass.MsgBody body = MsgBodyOuterClass.MsgBody.parseFrom(lastResult);
//这里就能拿到返回的集合列表了##################################
RadioCategoryResult.radio_category_rsp cityResult = RadioCategoryResult.radio_category_rsp.parseFrom(body.getBody());
ZLog.d("-----testProto cityResult:" + cityResult.toString());
RadioCategoryResult.errorinfo error = cityResult.getError();
ZLog.d("-----testProto error:" + error.toString());
List
for (int i = 0; i
ZLog.d("-----testProto getName:" + new String(radioList.get(i).getName().toByteArray()) + "---getId:" + radioList.get(i).getId());
}
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
2.前端要点
前端用到了protobuf.js这个库。请仔细阅读下面的文档, 并将其安装到当前前端工程。
这里我选择将proto编译成json文件,用到了pbjs这个工具。
所以先npm install pbjs --global安装之。
然后使用pbjs -t json src/proto/dsproto.proto -o src/proto/dsproto.json将其编译为json文件,这里为了方便,可以将此命令写入package.json:
这样每次proto文件变动后,只需要npm run proto即可同步更新。
接下来开始正式撸码:
一个全局helper类是必不可少的,例如:
将需要用到的类型缓存在protoHelper中。
于是,可以在websocket的onmessage方法中愉快的使用protobuf了:
protoHelper.Msg.decode(new Uint8Array(e.data))得到的便是Msg的实体了,可以发给上层业务逻辑进行处理。
当然,到此还并没有完。最为核心的一个配置,便是将你的websocket做如下设置:
ws.binaryType = 'arraybuffer'
protobuf总结
实现功能:数据格式protobuf编码解码;
环境:nodejs 版本9.11.0
引入的protobufjs 包:(此包为第三方包)
"protobufjs": “^6.8.8”,
protobuf 协议内容使用一致:编码解码根据协议体中内容进行;
发送端数据以 Request 发送, 接收端必须以Request解析;
引入的此版protobufjs之后,不需要根据原生protobuf 协议体去“重新”生成 相对应的js文件;
由于此功能发送端为c语言编写;当时传输到node端传输格式为pplication/octet-stream 格式(二进制流形式)
Node 接收的时候需要转化:
引入包;raw-body
具体使用:
Portobuf解码数据:根据传输端选择“协议”进行解码;
Protobuf编码数据;
返回时按照约定协议封装好数据之后,进行encode返回给设备端即可
参考资料 :私信‘资料'可MF领取相关资料,C++、linux,protobuf有十多年开发经验大牛帮解答,对大家应该很有帮助
本文来自投稿,不代表本人立场,如若转载,请注明出处:http://www.sosokankan.com/article/1889870.html