经过之前的学习,下面我们尝试定义一种消息格式,用于实现某种信息的获取和设置。该消息格式的定义需要实现下面的需求。
1)报文头:应该包含该消息格式版本的说明、通信共用的识别密码、考虑将来可能的扩展、命令类型标识;
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文献!