2.8 例子
经过之前的学习,下面我们尝试定义一种消息格式,用于实现某种信息的获取和设置。该消息格式的定义需要实现下面的需求。
1)报文头:应该包含该消息格式版本的说明、通信共用的识别密码、考虑将来可能的扩展、命令类型标识;
2)报文内容:报文唯一标识、错误状态、发生错误的位置、对象名称与值的绑定;其中错误状态包括没有错误、报文太大、报文携带的对象不存在、报文携带对象的值不合法、报文中某个对象的值不可以被更改(当设置一个只读对象时)、其他未知错误。
3)支持多种命令:获取对象、设置对象、命令的响应等三种命令。
对于第一条需求,它看起来像下面的样子,如图2-2所示。
对于第二条需求,它看起来像下面的样子,如图2-3所示。
图2-2 报文头示意图
图2-3 报文内容示意图
实现方案如下:
1)可以在ASN.1中将以上的报文格式定义为一个模块。
2)图2-2中的字段,可以分别使用ASN.1中的基础类型定义。INTEGER、OCTEC STRING、any字段由于其的不确定性,可以使用ANY类型作为占位符。由于其中的各项内容有严格的顺序要求,可以考虑使用SEQUENCE构造数据类型实现这种语义。
3)由于该报文支持3种命令,每次的命令只为其中一种,所以可以使用CHOICE类型。
4)图2-3中的内容是报文的主要内容。涉及字段定义、结构定义。我们可以使用INTEGER定义字段RequestID、ErrorStatus、ErrorIndex;由于报文内容格式一致且有顺序要求,使用SEQUENCE类型表示这种语义。为了区分命令种类,需要给每个命令标记唯一的识别码,这可以使用标签类型来实现。在这里,我们使用上下文指定标签类和隐式的方式来定义。
5)VarBindList具有列表性质,使用SEQUENCE OF定义。
结果看起来大概会是以下的样子:
-- 模块的定义 MYEXAMPLE-SNMP DEFINITIONS ::= BEGIN IMPORTS -- IMPORTS的使用方法 ObjectName, ObjectSyntax FROM RFC1155-SMI; Message ::= SEQUENCE { version INTEGER { version-1(0) }, community OCTET STRING, data ANY -- 扩展性考虑,见下面的PDUs } -- 命令种类定义 PDUs ::= CHOICE { get-request GetRequest-PDU, get-response GetResponse-PDU, set-request SetRequest-PDU, } GetRequest-PDU ::= [0] IMPLICIT PDU GetResponse-PDU ::= [2] IMPLICIT PDU SetRequest-PDU ::= [3] IMPLICIT PDU PDU ::= SEQUENCE { RequestID ::= INTEGER ErrorStatus ::= INTEGER { noError(0), tooBig(1), noSuchName(2), badValue(3), readOnly(4), genErr(5) } ErrorIndex ::= INTEGER -- 变量绑定 VarBind ::= SEQUENCE { name ObjectName, -- 对象名 value ObjectSyntax -- 对象值 } VarBindList ::= SEQUENCE OF VarBind } END -- 模块定义结束
实际上,该例子是仿照文献RFC1157中PDU定义的,其使用了本章大部分的知识,希望读者能明白各种数据类型的运用。如果把例子的讲解思路反过来的话,就是告诉读者如何阅读SNMP文献!