SNMP++之Snmp Class的对象模型(Object Modeling Technique)视图
|
Snmp class是SNMP++中最为重要的类。Snmp class封装了SNMP的会话。通过处理与指定代理端的会话,SNMP++(实现了)对网络管理应用的逻辑绑定。会话所控制的是PDU的构建、分发、接受。其他大多数API需要程序员直接操作会话,(也即)需要提供可靠的传输机制来控制超时、重发、查重。Snmp class管理了大部分的会话,得到解放的程序员只需要关注于代理端的管理,方便了代码的开发和测试。如果不这样(没有SNMP++),你就只有去设计、实现、测试你自己的SNMP引擎。(那么)Snmp class是如何管理通信的呢:1、在UDP或IPX连接基础上管理传输层;2、负责打包和解包PDU中的绑定变量(译注:前面讲到过的VB);3、分发和接收PDU;4、管理所有SNMP所需的资源。
Snmp class使用简单。它为网络管理应用提供了6种基本操作:Snmp::get, Snmp::set, Snmp::get_next, Snmp::get_bulk, Snmp::inform() 和 Snmp::trap(),每种操作都可分为阻塞和非阻塞(异步)两种方式。当有多个异步的操作同时申请通信时,需要采用多重通信。发送Notification的处理是通过Snmp::trap() 和 Snmp::inform(),即“陷阱”和“通知”的发送;接收标志信息的处理是通过Snmp::notify_register() 和 Snmp::notify_unregister(),即“陷阱”和“通知”的接收。
Snmp class使用安全。构造函数和析构函数完成了对所有资源的加载和卸载,(从而)减小了内存的崩溃和泄漏的可能性。所有SNMP的内部机制都隐藏起来了,也就避免了不小心而修改到这些内部机制。
Snmp class可移植。对操作系统和网络系统而言,Snmp class的接口是可移植的。绝大多数SNMP++的类都可以在任何ANSI / ISO C++编译器上编译和使用。(只需要)修改少量代码,就可以实现对SNMP++的平台切换。
Snmp Class Member Functions |
Description |
Constructor |
|
Snmp::Snmp( int &status); |
构造一个Snmp对象,status定义的是成功状态 |
Destructor |
|
Snmp::~Snmp( ); |
销毁,释放所有资源,关闭会话 |
Member Functions |
|
char * error_msg( const int status); |
返回所给错误状态的文本字符串 |
int get( Pdu &pdu, SnmpTarget &target); |
调用阻塞方式的SNMP get。从target获取Pdu |
int set( Pdu &pdu, SnmpTarget &target); |
调用阻塞方式的SNMP set。对target设置Pdu |
int get_next( Pdu &pdu, SnmpTarget &target); |
调用阻塞方式的SNMP get next。针对target上的Pdu |
int get_bulk( Pdu &pdu, SnmpTarget &target, const int non_repeaters, const int max_reps); |
调用阻塞方式的SNMP get bulk(但是V2 targets只使用get-next) |
int inform( Pdu &pdu, SnmpTarget &target); |
调用阻塞方式的inform |
int get( Pdu &pdu, SnmpTarget &target, snmp_callback callback, void * callback_data=0); |
调用SNMP异步get。从target获取Pdu,需要用到(用户)定义的回调和回调的参数 |
int set( Pdu &pdu, SnmpTarget &target, snmp_callback callback, void * callback_data=0); |
调用SNMP异步set。对target设置Pdu,需要用到(用户)定义的回调和回调的参数 |
int get_next( Pdu &pdu, SnmpTarget &target, snmp_callback callback, void * callback_data=0); |
调用SNMP异步get next。从target获取下一个Pdu,需要用到(用户)定义的回调和回调的参数 |
int get_bulk( Pdu &pdu, SnmpTarget &target, const int non_repeaters, const int max_reps snmp_callback callback, void * callback_data=0); |
调用SNMP异步get bulk。从target获取批量Pdu,需要用到(用户)定义的回调和回调的参数 |
int inform( Pdu &pdu, SnmpTarget &target, snmp_callback callback, void * callback_data=0); |
调用异步inform。需要用到notify的回调。 |
int trap( Pdu &pdu, SnmpTarget &target); |
向指定的target发送一个trap |
int notify_register( TargetCollection &targets, OidCollection &trapids, snmp_callback callback, void * callback_data=0); |
对接收trap和inform(的操作)注册 |
int notify_register( TargetCollection &targets, OidCollection &trapids, AddressCollection &listen_addresses, snmp_callback callback, void * callback_data=0); |
对接收trap和inform(的操作)注册,并用AddressCollection指出监听的接口。 |
int notify_unregister(); |
Un-register to receive traps and/or informs. 撤消对接收trap和inform(的操作)注册 |
int cancel( const unsigned long rid); |
Cancels a pending asynchronous request for a given request id. 取消(针对所给)请求id的异步请求的等待 |
所有的Snmp class成员函数都是双效的。(这就是说)对于SNMP version 1或version 2c ,他们可以使用统一的参数表。这解放了程序员,(因为程序员)不用为了与SNMP version 2的代理端通讯(而去)修改代码。
(通过)Snmp Class提供的许多成员函数可以创建、管理、终结一个会话。多个Snmp对象可以在同一时间建立。
Snmp Class的构造和析构函数允许开启和关闭会话。通过构建一个Snmp对象来开启一个Snmp会话。(由此可对)UDP或IPX套接口(实现)构建和管理,直到对象被销毁。Snmp对象可(选择)被动态或静态的实例化。
该构造函数以参数方式返回状态(status)。因为C++的构造函数没有返回值,调用者必须提供一个状态值(status)以供实例化对象后(针对状态的)检查。调用者需要检查返回值(是否)是“SNMP_CLASS_SUCCESS”。如果构造函数的状态不表示成功,该会话(也就)不可用。
// constructor, blocked SNMP object
Snmp::Snmp( int &status); // construction status
Snmp Class的析构函数关闭相应的会话,并释放所有资源和内存
// destructor
Snmp::~Snmp();
为了访问或修改代理端的MIB,请求必须通过Snmp::get(), Snmp::set(), Snmp::get_next(), Snmp::get_bulk(), Smnp::inform()以及Snmp::trap()(来发送)。所有这些成员函数接受同样的参数表。
(阻塞方式的)成员函数get允许从指定target的代理端获取对象。调用者必须指定目标target以及要请求的Pdu。
//--------[ get ]-------------------------------------------
int Snmp::get( Pdu &pdu, // Pdu to get
SnmpTarget &target); // specified target
(阻塞方式的)成员函数get next可以用来遍历代理端的MIB。
//---------[ get next ]--------------------------------------
int Snmp::get_next( Pdu &pdu, // Pdu to get next
SnmpTarget &target); // specified target
(阻塞方式的)成员函数set允许设置代理端的对象
//---------[ set ]--------------------------------------------
int Snmp::set( Pdu &pdu, // Pdu to set
SnmpTarget &target); // specified target
SNMP++为SNMP version 1和version 2的Target提供了一个获取批量(数据)的接口。在SNMP version 1中的(相应)操作对应到成员函数get next。
//--------[ get bulk ]-------------------------------------------
int Snmp::get_bulk( Pdu &pdu, // pdu to get_bulk
Target &target, // destination target
const int non_repeaters, // non repeaters
const int max_reps); // maximum reps
SNMP++提供了一个Inform接口,(由此可直接)在V2的代理端和网管端(内部之间)发送消息。
//-----------[ inform ]----------------------------------------------------------
int Snmp::inform( Pdu &pdu, // pdu to send
SnmpTarget &target); // destination target
为一个Inform指定其Id
Inform ID的指定方法与trap ID一样。(可通过)用成员函数Pdu::set_notify_id()来为一个inform的PDU指定其ID。Inform标识符(ID)代表了其使用的Oid。为了建立Inform ID,可以用需要的Inform ID值来直接建立一个Oid对象,然后用成员函数Pdu::set_notify_id()把一个Pdu加载(在其上)。反过来,一个inform的ID可以用成员函数Pdu::get_notify_id()来获取。
在Inform上指定TimeStamp(译注:时间信息)
要给一个inform PDU指定时间信息,可用成员函数Pdu::set_notify_timestamp()。如果一个Pdu没有用该成员函数就发出去了,那么会使用一个来自SNMP++引擎(默认的)timestamp。
一个Snmp实例可以支持阻塞与异步两种方式的请求。异步请求(将会)立即返回所控制的线程,并不需要等待呼叫者的应答。为了达到该目的,使用了所谓的回调程序机制。当发出异步请求时,调用者必须指定回调函数,(还可)选择性的指定一个回调函数的参数。
typedef void (*snmp_callback)( int, // reason
Snmp*, // session handle
Pdu &, // Pdu passed in
SnmpTarget &, // source target
void * ); // callback data
Reason(s) , int
该整形的原因参数描述了调用回调的原因。回调被调用的原因包括以下几种:
SNMP_CLASS_ASYNC_RESPONSE:收到了一个SNMP应答。这可以是一个(来自)get, set, get-next, get-bulk或inform的应答。用Pdu参数保存实际应答的PDU,用SnmpTarget参数保存发送应答的target。
SNMP_CLASS_TIMEOUT:一个SNMP++请求超时,该请求由target实例提供的超时与重发信息的机制(来处理)。为了重用,用 Pdu参数保存Pdu请求的原值,用SnmpTarget参数保存target的原值。
SNMP_CLASS_SESSION_DESTROYED:会话被销毁,(此时)所有正在等待的异步请求都不会完成。
SNMP_CLASS_NOTIFICATION:收到一个notification, trap或inform请求。Pdu对象会保存实际的notify,通过Pdu成员函数Pdu::get_notify_id(), Pdu::get_notify_timestamp()和Pdu::get_notifty_enterprise()来获得notification id, timestamp和enterprise。
Snmp++ Session, Snmp*
该参数保存发送请求的会话的值。由此可以在time-out或get-next情况下(实现)会话的重用。
Response PDU, Pdu&
该参数为esponse, notifie和trap保存了“应答 Pdu”。当“原因”(译注:前面提到的reason参数)为“失败”时,Pdu参数保存了“请求 Pdu”的原值。一旦Pdu对象越界,其值就不可得了。
Target , SnmpTarget&
该参数为response, notifie和trap保存了Pdu的来源。如果“原因”(译注:前面提到的reason参数)为“失败”,当有请求发出时,target的原值(就会)被用到。
Callback data ,void *
当有请求发出时,回调的参数可以作为一个可选的参数提供。如果指定了该参数,将会返回(相关)信息。如果没有指定,该值取空(null)。
SNMP++允许在完成之前取消(相应的)异步请求。这很有用,(尤其)当你需要在代码中提前退出或指定的回调已经失效的时候。当Snmp对象发出的请求被销毁时,异步请求会自动取消,这时指定的回调会收到一个“SNMP_CLASS_SESSION_DESTROYED”的原因。另一方面,可以用成员函数Snmp::cancel()来取消单个的异步请求。该成员函数通过参数request_id无影响的取消对应的异步请求。
//-------------[ cancel a request ]-----------------------------------
int Snmp::cancel( const unsigned long rid);
异步get允许从指定的代理端获取SNMP对象。当“请求PDU”发出后,异步get调用就会返回,它不会等待“应答PDU”。当收到“应答PDU”时,会调用程序员定义的回调。在回调中,可以用任何喜欢的方式实现有效的应答。
//------------------------[ get async ]----------------------------------
int Snmp::get ( Pdu &pdu, // Pdu to get async
SnmpTarget &target, // destination target
snmp_callback callback, // async callback
void * callback_data=0); // callback data
异步成员函数set的工作方式与get雷同。
//------------------------[ set async ]----------------------------------
int Snmp::set( Pdu &pdu, // Pdu to set async
SnmpTarget &target, // destination target
snmp_callback callback, // async callback
void * callback_data=0); // callback data
异步成员函数get-next的工作方式与异步get和set雷同。
//------------------------[ get next async ]-----------------------------
int Snmp::get_next( Pdu &pdu, // Pdu to get_next
SnmpTarget &target, // destination
snmp_callback callback, // async callback
void * callback_data=0); // callback data
异步成员函数get- bulk的工作方式与异步get和set雷同。
//------------------------[ get bulk async ]-----------------------------
int Snmp::get_bulk(Pdu &pdu, // Pdu to get_bulk async
Target &target, // destination target
const int non_repeaters, // non repeaters
const int max_reps, // max repetitions
snmp_callback callback, // async callback
void * callback_data=0); // callback data
//--------------------[ inform async ]----------------------------------------
int Snmp::inform( Pdu &pdu, // pdu to send
SnmpTarget &target, // destination target
snmp_callback callback, // callback function
void * callback_data=0); // callback data
SNMP++ API支持收发trap的成员函数
发送trap(的函数)是一个有用的管理程序(manager)API。可用函数与其他管理端进行通讯。
//-----------------------[ send a trap ]----------------------------------
int Snmp::trap( Pdu &pdu, // Pdu to send
SnmpTarget &target); // destination target
Pdu &pdu
要发送的Pdu,它是trap所包含的有效负载。
SnmpTarget &target
发送Trap的目的地
指定一个Trap的Id
Trap Id的指定方式与Inform Id(译注:后面会讲到)一样。可用成员函数Pdu::set_notify_id()来指定trap PDU的ID。Trap标识符(ID)在SMI SNMPv2中是以Oid表示的。SNMP++预定义了以下6种通用的trap Oid。(只需)用想要的trap id值来赋给一个Oid对象就可以生成一个trap id。相反的,可用成员函数Pdu::get_notify_id()来获取trap id。
SNMP++为通用Trap ID定义的Oid对象
coldStart (" 1.3.6 .1.6.3.1.1. 5.1” )
warmStart (" 1.3.6 .1.6.3.1.1. 5.2” )
linkDown (" 1.3.6 .1.6.3.1.1. 5.3” )
linkUp (" 1.3.6 .1.6.3.1.1. 5.4” )
authenticationFailure (" 1.3.6 .1.6.3.1.1. 5.5” )
egpNeighborLoss (" 1.3.6 .1.6.3.1.1. 5.6” )
如果要发送(某个)企业指定的trap,调用者可能需要指定一个除上面以外的Oid。
指定Trap的时间信息
可用成员函数Pdu::set_notify_timestamp()来指定trap PDU的时间信息。如果一个Pdu没调用这个成员函数就发送了,那么会使用一个来自SNMP++引擎的时间信息。
不用被企业指定的trap困扰,任何trap的企业都代表了产生trap的代理端的MIB。对trap的发送者(来说)它是系统标识符(System Object Identifier),但是从理论上讲它可以表示任何Oid的值。为了设置该参数,SNMP++允许使用成员函数Pdu::set_notify_enterprise()来设置enterprise,而且这个(参数)是可选的。如果使用了所提供的enterprise,(该enterprise)会加载在对应的Pdu对象上。
为了给SNMPv1 Trap指定特殊的Trap值,trapid的Oid应该构造如下:trapid 的最末子id(subid)代表指定的要使用的值;倒数第二个子id应该是零。即,为了指定特殊的Trap值,需要添加两个额外的子id,一个是零、一个是值(“0.X”)。这个约定与规定SNMPv1和SNMPv2trap映射的RFC 1452(的描述)一致。
接收SNMP++ trap和inform(的时候),允许应用程序使用指定的过滤器来接收trap和inform。不像其他的SNMP操作,trap和inform是在任何可能出现的时候主动发出的。因此informs和traps属于异步的动作。通过SNMP++提供的成员函数,调用者(可以)指定informs和traps的过滤器。可用informs和traps的类型、来源和目标来过滤informs和traps。
//-----------------------[ register to receive traps and informs]-------------------------------------------
// default form listens on all local interfaces using well known port/ socket #’s
int Snmp::notify_register(OidCollection &ids, // types to listen for
TargetCollection &targets, // targets to listen for
snmp_callback callback, // callback to use
void *callback_data=0); // optional callback data
//------------------------[ register to receive traps and informs ]----------------------------------------
// alternate form, AddressCollection allows local listen interface specification
int Snmp::notify_register(OidCollection &ids, // types to listen for
TargetCollection &targets, // targets to listen for
AddressCollection &local_interfaces, // interfaces to listen on
snmp_callback callback, // callback to use
void *callback_data=0); // optional callback data
//-----------------------[ un-register to get traps and informs]------------------------------------------
int Snmp::notify_unregister();
每个Snmp class实例可以为它们自己的traps / informs注册。也就是说,一个Snmp对象可以有它自己的一套过滤器和回调,当收到的trap或inform满足过滤条件时就会调用。当每个新的呼叫清理了先前的过滤器设置时,成员函数Snmp::notify_register()可能会多次被调用。当调用成员函数Snmp:notify_unregister()或Snmp实例撤消时,相应的接收Trap / inform的会话将会终止。
notification的注册基本形式中包括:notification类型、notification来源、过滤参数、OidCollection和TargetCollection。使用该形式的notify_register()会在所有本地端口上触发notification的监听。所以如果本地机器有多重初始地址(即它会有多重网络接口),所有的接口将会被开启,并使用已知的port / socket来接收notify。例如:如果我的机器是双网卡的,两个卡都支持IP(Internet Protocol)协议,其中一个还支持IPX(Internet Exchange Protocol)协议;(如果)调用基本形式的notify_register(),则会在两个IP接口上使用已知的SNMP trap端口,在IPX接口上使用已知的trap IPX套接字(socket number)。
作为备用,重载形式的notify_register()可接受一个附加参数,进而允许指定本地接口来监听inform或AddressCollection。AddressCollection参数包含了一组需要监听的Address对象列表,包括:IpAddresses, IpxAddresses, UdpAddresses 和 IpxSockAddresses。下表描述了AddressCollection以及notify_register()的运作方式:
AddressCollection Element Behavior Definition
Address Class |
Value |
Description |
IpAddress |
Any value except 0.0.0 .0 |
用已知的IP端口监听指定的IP接口 |
IpAddress |
0.0.0 .0 |
用已知的IP端口监听所有IP接口 |
UdpAddress |
Any value except 0.0.0 .0 |
用已知的UDP端口监听指定的UDP接口 |
UdpAddress |
0.0.0 .0 |
用已知的UDP端口监听所有UDP接口 |
IpxAddress |
Any value except 00000000:000000000000 |
用已知的IPX端口监听指定的IPX接口 |
IpxAddress |
00000000:000000000000 |
用已知的IPX端口监听所有IPX接口 |
IpxSockAddress |
Any value except 00000000:000000000000 |
用已知的IPX套接字监听指定的IPX接口 |
IpxSockAddress |
00000000:000000000000 |
用已知的IPX套接字监听所有IPX接口 |
当(需要)过滤时,过滤器的行为(如下):如果收到的inform或trap与OidCollection中的id单元(item)一致,并且收到的inform或trap与TargetCollection中的单元一致,则相应的inform / trap会被送到调用者指定的回调中。注意,如果OidCollection为空,则所有的inform都将通过id检查,(同样的)如果TargetCollection为空,则所有的inform都将通过Target检查。
SNMP++提供了3种有序集合的collection classe,共同来收集Oids, Targets和Addresses。所有collection classe操作形式都一样,因为它们是从同样的C++模板类SnmpCollection派生来的。统一的集合操作如下:
Target and Oid Collection Class Member Functions |
Description |
Constructors |
|
SnmpCollection::SnmpCollection(void); |
构造一个空的集合 |
SnmpCollection::SnmpCollection(const T &t ); |
用单一元素构造一个集合 |
Destructors |
|
SnmpCollection::SnmpCollection(); |
销毁集合,释放所有资源 |
Member Functions |
|
int size(); |
返回集合的大小 |
SnmpCollection & operator += ( T &t); |
增加一个元素到集合 |
SnmpCollection & operator = (SnmpCollection &collection); |
将一个集合赋给另一个 |
T& operator[]( int p); |
访问集合中的一个元素 |
int set_element( const T& i, const int p); |
在集合种设置一个已有的元素 |
int get_element( T& i, const int p); |
从集合获取一个元素 |
生成并使用SnmpCollections作为接收一个trap / inform的过滤器是简单而直接的。Notify的注册(函数)有3个参数:TargetCollection, OidCollection和AddressCollection。要构造这些过滤器,首先得实例化一个集合,然后用重载的操作符“+=”把元素加入其中。
// example of making trap reception filters
// target collection
TargetCollection my_targets;
my_targets += cisco_router;
my_targets += fore_switch;
// Oid collection
OidCollection my_trapids;
my_trapids += coldStart;
my_trapids += warmStart;
// Address collection
AddressCollection my_addresses;
my_addresses += (IpAddress) “ 10.4.8 .5”;
my_addresses += (GenAddress) “01020304: 010203040506” ;
使用SNMP++时,可返回多种(错误)编号。这些错误号可穿越平台,进而帮助应用的开发者发现并检查错误条件。
如果在使用Snmp成员函数过程中出现了一个错误,成员函数Snmp::error_msg( )可以用来检索出一个友好的错误字符串。
//------------------------[ error message]-----------------------------
char * Snmp::error_msg( const int status); // returns string for provided status