3.10.通过双效的API支持SNMPv1和SNMPv2.11
3.11.支持SNMP的Get,GetNext,GetBulk,Set,Inform和Trap的操作...11
4.在MicrosoftWindows系列操作系统上使用SNMP++.12
4.3.对Notification、Trap收发的支持...12
4.4.与HPOpenViewforWindows兼容...12
9.2.TimeTicksClass的成员函数列表...22
10.2.Counter32Class的成员函数列表...24
12.2.Counter64Class的成员函数列表...28
13.8.UdpAddresses和IpxSockAddresses.33
13.8.2.用IpxSockAddresses发送请求...33
13.8.3.用UdpAddress和IpxSockAddress接收Notification.33
14.1.VariableBindingClass成员函数列表...36
14.2.2.VbClass的GetOid/SetOid成员函数...38
14.2.3.VbClass的GetValue/SetValue成员函数...38
14.2.4.用一个GenAdress对象设置value.39
14.2.5.用一个UdpAdress对象设置value.39
14.2.6.用一个IpxSockAdress对象设置value.40
14.2.7.用一个Octet对象设置value部分...40
14.2.8.VbClass成员函数:GetValue.40
15.5.PduClass处理Traps和Informs的成员函数...47
17.5.CTargetClass(以Community为基础的Target)52
17.5.1.CTarget对象可通过3种不同的方式构建...53
18.3.4.SnmpClass发送请求的成员函数...57
18.3.5.SnmpClass的阻塞方式成员函数:Get57
18.3.6.SnmpClass的阻塞方式成员函数:GetNext57
18.3.7.SnmpClass的阻塞方式成员函数:Set58
18.3.8.SnmpClass的阻塞方式成员函数:GetBulk.58
18.3.9.SnmpClass的阻塞方式成员函数:Inform..58
18.4.5.SnmpClass的异步成员函数:GetNext60
18.4.6.SnmpClass的异步成员函数:GetBulk.60
18.4.7.SnmpClass的异步成员函数:Inform..60
18.5.3.使用OidCollection,TargetCollection和AddressCollections过滤...63
18.6.1.SnmpClass的错误消息成员函数...64
19.1.MicrosoftWindows事件驱动系统的运作...65
19.2.OpenSystemsFoundation(OSF)X11Motif的运作...65
22.1.GettingaSingleMIBVariableExample.69
22.2.GettingMultipleMIBVariablesExample.69
22.3.SettingaSingleMIBVariableExample.71
22.4.SettingMultipleMIBVariablesExample.71
22.5.WalkingaMIBusingGet-NextExample.72
SNMP++框架的对象模型(ObjectModelingTechnique)视图
目前有许多可以创建网络管理应用的SNMP的API。大多数API都提供了一个很大的函数库,调用这些函数的程序员需要熟悉SNMP内部的工作原理和它的资源管理机制。这些API大多都是平台相关的,导致了SNMP的代码也成了操作系统相关的或者网络系统平台有关的,难以移植。另一方面由于C++有丰富的、可复用的标准类库,用C++开发应用成了目前的主流,然而C++标准类库所缺少的正是一套封装好的处理网络管理的类。如果基于面向对象的方法来进行SNMP网络编程,可以提供以下诸多好处:易用、安全、可移植、能扩展。因此SNMP++灵活有效的解决了其他类似API执行和管理起来都很痛苦的问题。
SNMP++是一套C++类的集合,它为网络管理应用的开发者提供了SNMP服务。SNMP++并非是现有的SNMP引擎的扩充或者封装。事实上为了效率和方便移植,它只用到了现有的SNMP库里面极少的一部分。SNMP++也不是要取代其他已有的SNMPAPI,比如WinSNMP。SNMP++只是通过提供强大灵活的功能,降低管理和执行的复杂性,把面向对象的优点带到了网络编程中。
面向对象的SNMP编程应该是简单易用的。毕竟,SNMP原意就是“简单网络管理协议”,SNMP++只是将简单还给SNMP!应用的开发者不需要关心SNMP的底层实现机制,因为面向对象的方法已经将SNMP内部机制封装、并隐藏好了。SNMP++的简单易用表现在以下方面:
1.2.1.1.为SNMP提供了简单易用的接口
使用SNMP++不需要精通SNMP,甚至不需要精通C++!因为SNMP++里面几乎没有C的指针,所以可以简单的通过API直接使用。
1.2.1.2.可以方便的迁移至SNMPv2
SNMP++的主要目标之一就是开发一套API,使得迁移至SNMPv2的过程中尽可能少地影响现有代码。SnmpTargetclass使之成为了可能。
1.2.1.3.保留了对SNMP灵活的底层开发
这是为了方便那些不希望使用面向对象方法,而直接编写SNMP的底层机制的用户。虽然SNMP++快速而方便,但是有些时候程序员也许希望直接使用底层的SNMPAPI。
1.2.1.4.鼓励程序员用功能强大的C++,不要因学得不够快而去指责它
使用SNMP++的用户不需要精通C++。基本的SNMP的知识是必要的,但是实际上也需要对C++初步的理解。
大多数SNMPAPI需要程序员去管理大量的资源。不恰当的装载或卸载这些资源,会导致内存崩溃或泄漏。SNMP++提供的安全机制,可以实现对这些资源的自动管理。SNMP++的用户可以体验到自动管理资源与对话所带来的好处。SNMP++在编程上的安全突出表现在下面的领域:
1.2.2.1.为SNMP资源提供安全的管理
这包括对SNMP的结构、会话以及传输层的管理。SNMPclass被设计成所谓的抽象数据类型(ADT),隐藏了私有数据,而通过提供公有的成员函数来访问或修改这些隐藏了的实例变量。
1.2.2.2.提供查错、自动超时重发的机制
SNMP++的用户不需要关心如何为不可靠的网络传输机制提供可靠性。可能出现的通信错误包括:数据包丢失、数据包重复以及反复提取数据包。SNMP++消除了所有这些问题出现的可能性,为用户提供了传输层的可靠性。
SNMP++的主要目的之一就是提供一套可移植的API,进而穿越各种操作系统(Os)、网络系统(NOS)以及网络管理平台。由于SNMP++隐藏了内部机制,所以从各个平台的角度来看SNMP++的公用接口都是一样的。使用SNMP++的程序员不需要为平台迁移去修改代码。另一个移植方面的问题是在多种协议上运行的能力。目前,SNMP++能运行在IP协议和IPX协议上,或者两者都可以。
扩充不应该只是多一种选择,而是更深层次的。SNMP++不仅是可扩充,而且是很容易扩充。SNMP++的扩充囊括了对下列领域的支持:新的操作系统、网络系统、网络管理平台、网络协议、SNMPv2及其新特性。通过派生C++的类,SNMP++的用户可以根据自己的喜好继承、重载。
1.2.4.1.重载SNMP++的基础类
应用的开发者可以通过派生出SNNP++的子类来提供所需的操作和属性,这正是面向对象的核心主题。SNMP++的基础类被打造成通用的、没有包含任何具体的数据结构和操作。通过C++派生类以及重新定义虚函数,可以很容易的添加新属性。
在开始介绍SNMP++的各种特性之前,这里先举个简单的例子来展现它的强大和简单。该例子是从指定的代理端上获取SNMPMIB的系统描述符(SystemDescriptorobject)。包含了创建一个SNMP++会话、获取系统描述符,并打印显示出来的所需的所有代码。其中重发和超时机制已经被SNMP++自动管理了。以下属于SNMP++的代码,采用粗体显示。
#include“snmp_pp.h”
#defineSYSDESCR“1.3.6.1.2.1.1.1.0”//ObjectIDforSystemDescriptor
voidget_system_descriptor()
{
intstatus;//returnstatus
CTargetctarget((IpAddress)“10.4.8.5”);//SNMP++communitytarget
Vbvb(SYSDESCR);//SNMP++VariableBindingObject
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
//-------[InvokeaSNMP++Get]-------------------------------------------------------
pdu+=vb;//addthevariablebindingtothePDU
if((status=snmp.get(pdu,ctarget))!=SNMP_CLASS_SUCCESS)
cout<<snmp.error_msg(status);
else{
pdu.get_vb(vb,0);//extractthevariablebindingfromPDU
cout<<“SystemDescriptor=”<<vb.get_printable_value();}//printoutthevalue
};//Thatsall!
真正属于SNMP++的语句就10行代码。首先用代理端的IP地址建立一个CTarget对象;然后用MIB对象所定位的系统描述符创建一个变量绑定(Vb);接着就把这个Vb纳入一个Pdu对象;最后生成一个Snmp对象来执行SNMP的get操作。一旦找到了所需的数据,对应的应答消息就被打印出来。另外,所有的处理错误代码也都包含在内了。
SNMP++是以一套C++类作为基石的。这些类是:对象描述符(Oid)类、变量绑定(Vb)类、协议数据单元(Pdu)类、Snmp类。并且,其他各种用抽象语法表示(ASN.1)来描述的管理信息结构(SMI),也被抽象成了简单的、面向对象的类型。
3.2.SNMP内存的自动管理
当SNMP++的对象被实例化或销毁的时候,其相关的类可以自动管理着各种各样的SNMP结构和资源。这就使得应用的开发者不用再担心数据结构和资源的卸载,不然就得为防止内存的崩溃或者泄漏提供有效的保护措施。SNMP++的对象的实例化可以是静态的,也可以是动态的。静态的实例化可以在对象脱离它的作用域时卸载掉;动态分配则需要使用C++的new和delete。在SNMP++内部,有许多被隐藏和保护在公用接口后面的SMI结构。所有的SMI结构都是在内部管理的,程序员不需要定义或管理SMI的结构和它的值。因为在SNMP++内绝大部分地方是不存在C的指针的。
由于隐藏并管理了所有SMI结构和它们的值,SNMP++的类使用起来即简单又安全。外部程序员无法破坏到隐藏和保护在作用域后面的东东。
SNMP++提供了强大灵活的功能,降低了管理和执行的复杂性。每个SNMP++对象都通过建立一个会话来和一个代理端联系。即由一个SNMP++的对话类的实例,就能处理所有与特定代理端的连接。另外自动重发和超时控制的机制,为每个SNMP++对象都带来了可靠性。一个应用可能会包含许多SNMP++的对象的实例,每个实例都可能与相同或不同的代理端通话。有了这个功能强大的特性,网络管理程序就可以为每个管理单元建立起不同的会话。另一方面,就算单一的SNMP会话也可以解决问题。例如:一个应用可以通过一个SNMP++对象来处理图形统计,另一个SNMP++对象监控trap,也许还有第三个SNMP++对象用以浏览SNMP。SNMP++自动并行处理了同一时刻来自不同SNMP++实例的请求。
SNMP++的主体是可以移植的C++代码。其中只有SnmpClass的实现与不同的目标操作系统有关。如果你的程序中包含了SNMP++的代码,那么导出这部分代码的时候,就可以不做任何修改。
3.6.自动超时和重发机制
SNMP++提供了自动超时和重发机制,程序员不用去实现超时或重发机制的代码。重发机制是在SnmpTargetClass里面定义的,这就使得每一个目标(Target)都具有了它自己的超时/重发机制。
SNMP++提供了阻塞方式。MS-Windows上的阻塞方式可以并发的阻塞从每个SNMP类的实例发出的请求。
SNMP++还为应答提供了异步的非阻塞的方式。超时和重发机制同时支持阻塞和异步两种模式。
SNMP++允许在多种传输层上(包括IP和IPX)收发trap。而且SNMP++还允许使用非标准的IP端口和IPX套接口来收发trap。
3.10.通过双效的API支持SNMPv1和SNMPv2
SNMP++的设计可同时支持SNMPv1和SNMPv2的使用。所有API的操作都被设计成了双效的,也即操作是SNMP版本无关的。通过使用SnmpTarget类,与SNMP的版本相关的操作被抽象出来了。
3.11.支持SNMP的Get,Inform和Trap的操作
SNMP++完整的支持SNMP的6种操作。这6个SNMP++的成员函数使用相同的参数表,也都支持阻塞和非阻塞(异步)方式。
SNMP++是用C++实现的,所以允许程序员重载或重定义那些不适合他们的操作。举个例子:如果一个应用需要特定的Oid对象,那就需要建立一个OidClass的子类,用以继承所有Oid类的属性和操作,同时在派生类种加入新的属性和操作。
4.在MicrosoftWindows系列操作系统上使用SNMP++
SNMP++已经在MS-Windows3.1,MS-WindowsForWorkGroups3.11,MS-WindowsNT3.51,andMS-Windows’95上实现了。
在MS-Windows上可以用WinSNMPVersion1.1来运行SNMP++。这就使得其他用WinSNMP代码直接写的SNMP应用可以与SNMP++的应用兼容。注意,目前HP的MS-Windows设备使用WinSNMP,其他设备不需要使用WinSNMP来进行ANS.1的编码和解码。但那些没有使用WinSNMP的设备也需要与WinSNMP的应用兼容,才能和SNMP++的应用兼容。
4.2.对IP和IPX的支持
可以通过一个WinSockcompliantstack,来实现对IP的操作。同时为了在IPX协议上运行,还需要兼容Novell网络的客户程序和驱动。目前SNMP++已经通过了在广泛多样的协议栈下的运行测试,这些协议栈包括:FTP,Netmanage,LanWorkPlace,MS-WFWG3.11,以及WindowsNT。
4.3.对Notification、Trap收发的支持
SNMP++包含了对WinSNMPtrap机制的支持。这同时包括了trap的发送和收取。在接收trap的时候,还提供了过滤trap的功能。
已经有大量使用SNMP++创建的应用,实现了HPOpenViewforWindows的兼容。
用在UNIX设备上的SNMP++类的接口和MS-Windows是一样的。
通过编译、连接对应的SNMP++类,SNMP++就可以实现在UNIX上运行。SNMP++/UNIX的设计决定了它可以同时运行在原始的UNIX字符模式、X-Window模式,或者Windows-to-UNIX的仿真工具上。
已经有大量使用SNMP++创建的应用,实现了与HPOpenViewforUNIX的兼容。
6.SNMPSyntaxClasses
SNMP++之SNMPSyntax的对象模型(ObjectModelingTechnique)视图
SNMP++的SNMPSyntaxclasse描绘了一个具有C++面向对象风格的视图。即用于描述SNMP的SMI之ASN.1的数据类型视图。它包含了映射到对应的SMI类型的一组类的集合。而且为了方便使用,还引入了一些非SMI的类。SNMP++为这些SNMP数据类型提供了强大、简单易用的接口。下表概要地描述了各种SNMP++Syntaxclasses:
SNMP++SyntaxClassName |
ClassDescription |
SMIorASN.1Counterpart |
SnmpSyntax |
ParentofallSyntaxclasses. |
NoASN.1counterpart,usedforOOstructure. |
Oid |
Objectidentifierclass. |
ASN.1ObjectIdentifier. |
OctectStr |
Octetstringclass. |
ASN.1Octetstring. |
Uint32 |
Unsigned32bitintegerclass. |
SMIunsigned32bitinteger. |
TimeTicks |
TimeTicksclass. |
SMItimeticks. |
Counter32 |
32bitcounterclass. |
SMI32bitcounter. |
Gauge32 |
32bitgaugeclass. |
SMI32bitgauge. |
Int32 |
Signed32bitinteger. |
SMI32bitsignedinteger. |
Counter64 |
64bitcounterclass. |
SMI64bitcounter. |
Address |
Abstractaddressclass. |
NoASN.1counterpartusedforOOstructure. |
IpAddress |
IPaddressclass. |
SMIIPaddress. |
UdpAddress |
UdpAddressclass |
SMIIPaddresswithportspecification. |
IpxAddress |
IPXaddressclass. |
NoASN.1orSMIcounterpart |
IpxSockAddress |
IPXAddressclasswithsocketnumber. |
NoASN.1orSMIcounterpart |
MacAddress |
MACaddressclass. |
SMIcounterpart |
GenAddress |
GenericAddress |
NoASN.1orSMIcounterpart. |
7.ObjectIdClass
SNMP++之OidClass的对象模型(ObjectModelingTechnique)视图
对象标识符类(Oid)封装了SMI的对象标识。信息管理库(MIB)中所定义的SMI的对象是一种在MIB中找到的数据元素的数据标识。与SMIOid相关的结构和函数,自然都是面向对象的。事实上Oidclass与C++的Stringclass有许多共同之处。如果你熟悉C++的Stringclass或者MFC的CStringclass,那么你就会感觉Oidclass用起来很亲切、简单。Oidclass被设计成了快速有效的类;它可以定义和操作对象标识;不依赖现有的SNMPAPI,完全是可移植的;可以在任何ANSIC++编译器上进行编译。
7.2.OidClass的成员函数列表
OidClassMemberFunctions |
说明 |
Constructors |
|
Oid::Oid(void); |
构造一个空的的Oid |
Oid::Oid(constchar*dotted_string); |
用带点的字符串构造新的Oid |
Oid::Oid(constOid&oid); |
用已有的Oid构造新的Oid |
Oid::Oid(constunsignedlong*data,intlen); |
通过一个指针和长度来构造一个新的Oid |
Destructor |
|
Oid::~Oid(); |
销毁一个Oid,释放所有的堆 |
OverloadedOperators |
|
Oid&operator=(constchar*dotted_string); |
将一个带点的字符串付给一个Oid |
Oid&operator=(constOid&oid); |
将一个Oid付给另一个Oid |
intoperator==(constOid&lhs,constOid&rhs); |
判断两个Oid是否相等 |
intoperator==(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否和一个带点的字符串相等 |
intoperator!=(constOid&lhs,constOid&rhs); |
判断两个Oid是否不等 |
intoperator!=(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否和一个带点的字符串不相等 |
intoperator<(constOid&lhs,constOid&rhs); |
判断一个Oid是否比另一个小 |
intoperator<(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否比一个带点的字符串小 |
intoperator<=(constOid&lhs,constOid&rhs); |
判断一个Oid是否“小于等于”另一个 |
intoperator<=(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否“小于等于”一个带点的字符串 |
intoperator>(constOid&lhs,constOid&rhs); |
判断一个Oid是否比另一个大 |
intoperator>(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否比一个带点的字符串大 |
intoperator>=(constOid&lhs,constOid&rhs); |
判断一个Oid是否“大于等于”另一个 |
intoperator>=(constOid&lhs,constchar*dotted_string); |
判断一个Oid是否“大于等于”一个带点的字符串 |
Oid&operator+=(constchar*dotted_string); |
将一个带点的字符串加到一个Oid后面 |
Oid&operator+=(constunsignedlongi); |
将一个整数加到一个带点的Oid字符串后面 |
Oid&operator+=(constOid&oid); |
将一个Oid加到另一个Oid后面 |
unsignedlong&operator[](intposition); |
访问Oid的一个独立子单元 |
OutputMemberFunctions |
|
char*get_printable(constunsignedintn); |
返回一个Oid的n个带点格式的子单元 |
char*get_printable(constunsignedlongs,constunsignedlongn); |
返回从s开始,以点号分割的n个子单元 |
char*get_printable(); |
返回以点号分割的Oid字符串 |
operatorchar*(); |
同上 |
MiscellaneousMemberFunctions |
|
set_data(constunsignedlong*data,constunsignedlongn); |
用指针和长度来设置一个Oid |
unsignedlonglen(); |
返回Oid中子单元的个数(长度) |
trim(constunsignedlongn=1); |
|
nCompare(constunsignedlongn,constOid&oid); |
从左至右比较Oid的前n个子单元 |
RnCompare(constunsignedlongn,constOid&oid); |
从右至左比较Oid的后n个子单元 |
intvalid(); |
返回Oid的有效性 |
下面的例子展示了OidClass的不同用法。OidClass不需要依赖其他库和模块。下列代码在ANSI/ISOC++上编译通过
#include“oid.h”
voidoid_example()
{
//constructanOidwithadottedstringandprintitout
Oido1("1.2.3.4.5.6.7.8.9.1");
cout<<“o1=“<<o1.get_printable();
//constructanOidwithanotherOidandprintitout
Oido2(o1);
cout<<“o2=”<<o2.get_printable();
//trimo2’slastvalueandprintitout
o2.trim(1);
cout<<“o2=”<<o2.get_printable();
//adda2valuetotheendofo2andprintitout
o2+=2;
cout<<“o2=”<<o2.get_printable();
//createanewOid,o3
Oido3;
//assigno3avalueandprintitout
o3="1.2.3.4.5.6.7.8.9.3";
cout<<“o3=”<<o3.get_printable();
//createo4
Oido4;
//assigno4o1’svalue
o4=o1;
//trimoffo4by1
o4.trim(1);
//concata4ontoo4andprintitout
o4+=”.4”;
cout<<“o4=”<<o4.get_printable();
//makeo5fromo1andprintitout
Oido5(o1);
cout<<“o5=”<<o5.get_printable();
//comparetwonotequaloids
if(o1==o2)cout<<"O1EQUALSO2";
elsecout<<"o1notequaltoo2";
//printoutapieceofo1
cout<<"strval(3)ofO1=“<<o1.get_printable(3);
//printoutapieceofo1
cout<<"strval(1,3)ofO1=“<<o1.get_printable(1,3);
//seto1'slastsubid
o1[o1.len()-1]=49;
cout<<"O1modified=“<<o1.get_printable();
//seto1's3rdsubid
o1[2]=49;
cout<<"O1modified=“<<o1.get_printable();
//getthelastsubidof02
cout<<"lastofo2=“<<o2[o2.len()-1];
//getthe3rdsubidof02
cout<<"3rdofo2=“<<o2[2];
//ncompare
if(o1.nCompare(3,o2))
cout<<"nCompareo1,o2,3==";
else
cout<<"nCompareo1,3!=";
//makeanarrayofoids
Oidoids[30];intw;
for(w=0;w<30;w++)
{
oids[w]="300.301.302.303.304.305.306.307";
oids[w]+=(w+1);
}
for(w=0;w<25;w++)
{
sprintf(msg,"Oids[%d]=%s",w,oids[w].get_printable());
printf(“%s”,msg,strlen(msg));
}
}
SNMP++之OctetStrClass的对象模型(ObjectModelingTechnique)视图
通过SNMP++的Octetclass,可以简单且安全地操作SMI的8位字节。有了Octetclass,就不需要通过内部指针和长度来操作8位字节了。使用SNMP++的Octetclass来实例化、操作、销毁一个8位字节对象是很简单的,不用担心如何管理内存以及内存是否会泄漏。与ANSIC++的stringclass类似,OctetStrclass可以通过多种方法构造8位字节,还可以对它们进行赋值操作,与其他SNMP++classes一起使用。
8.2.OctetStrClass的成员函数列表
OctetStrClassMemberFunctions |
说明 |
Constructors |
|
OctetStr::OctetStr(void); |
构造一个空的OctetStr |
OctetStr::OctetStr(constchar*string); |
用一个没有结束符的字符串构造OctetStr |
OctetStr::OctetStr(constunsignedchar*s,unsignedlonginti); |
通过一个指针和长度来构造OctetStr |
OctetStr::OctetStr(constOctetStr&octet); |
用已有的OctetStr构造新的OctetStr |
Destructor |
|
OctetStr::~OctetStr(); |
销毁一个OctetStr |
OverloadedOperators |
|
OctetStr&operator=(constchar*string); |
将一个没有结束符的字符串付给一个OctetStr |
OctetStr&operator=(constOctetStr&octet); |
将一个OctetStr付给另一个OctetStr |
intoperator==(constOctetStr&lhs,constOctetStr&rhs); |
判断两个OctetStr对象是否相等 |
intoperator==(constOctetStr&lhs,constchar*string); |
判断OctetStr是否和一个char*字符串相等 |
intoperator!=(constOctetStr&lhs,constOctetStr&rhs); |
判断两个OctetStr对象是否不相等 |
intoperator!=(constOctetStr&lhs,constchar*string); |
判断OctetStr是否和一个char*字符串不相等 |
intoperator<(constOctetStr&lhs,constOctetStr&rhs); |
判断一个OctetStr是否比另一个小 |
intoperator<(constOctetStr&lhs,constchar*string); |
判断一个OctetStr是否比另一个char*字符串小 |
intoperator<=(constOctetStr&lhs,constOctetStr&rhs); |
判断一个OctetStr是否“小于等于”另一个 |
intoperator<=(constOctetStr&lhs,constchar*string); |
判断一个OctetStr是否“小于等于”一个char*的字符串 |
intoperator>(constOctetStr&lhs,constOctetStr&rhs); |
判断一个OctetStr是否比另一个大 |
intoperator>(constOctetStr&lhs,constchar*string); |
TestifoneOctetStrisgreaterthanachar*. 判断一个OctetStr是否比一个char*的字符串大 |
intoperator>=(constOctetStr&lhs,constOctetStr&rhs); |
判断一个OctetStr是否“大于等于”另一个 |
intoperator>=(constOctetStr&lhs,constchar*); |
判断一个OctetStr是否“大于等于”一个char*的字符串 |
OctetStr&operator+=(constchar*string); |
在一个OctetStr后面连接一个字符串 |
OctetStr&operator+=(constunsignedcharc); |
在一个OctetStr后面连接一个单字符 |
OctetStr&operator+=(constOctetStr&octetstr); |
将两个OctetStr连接在一起 |
unsignedchar&operator[](intpositioni); |
用数组的形式来访问一个OctetStr |
Miscellaneous |
|
voidset_data(constunsignedchar*s,unsignedlongl); |
用指针和长度来设置一个OctetStr |
intnCompare(constunsignedlongn,constOctetStr&o); |
与另一个OctetStr比较前n个元素 |
unsignedlonglen(); |
返回一个OctetStr的长度 |
intvalid(); |
返回一个OctetStr的有效性 |
unsignedchar*data(); |
返回一个指向内部数据的指针 |
char*get_printable(); |
格式化输出,如果不是ASCII则按16进制处理 |
char*get_printable_hex(); |
按16进制格式,进行格式化输出 |
当输出一个OctetStr对象时,如果该8位字节所包含的字符不是ASCII码,对成员函数char*或者get_printable()的调用,就会自动转换成对成员函数get_printable_hex()的调用。这就使得使用者只需要简单地使用成员函数char*或get_printable()来进行输出。而成员函数get_printable_hex()是专门用来把OctetStr按16进制格式输出的。
//OctetClassExamples #include“octet.h” voidoctet_example() { OctetStroctet1;//createaninvalidun-initializedoctetobject OctetStroctet2(“RedHookExtraBitterAle”);//createanoctetwithastring OctetStroctet3(octet2);//createanoctetwithanotheroctet unsignedcharraw_data[50];//createsomerawdata OctetStroctet4(raw_data,50);//createanOctetStrusingunsignedchardata octet1=“SierraNevadaPaleAle”;//assignoneoctettoanother cout<<octet1.get_printable();//showoctet1asanullterminatedstring cout<<octet4.get_printable_hex();//showoctet4asahexstring cout<<(char*)octet1;//sameasget_printable() if(octet1==octet2)//comparetwooctets cout<<“octet1isequaltooctet2”; octet2+=“WinterFestAle”;//concatastringtoanOctet if(octet2>=octet3) cout<<“octet2greaterthanorequaltooctet2”; octet2[4]=‘b’;//modifyanelementofanOctetStrusing[]’s cout<<octet.len();//printoutthelengthofanOctetStr unsignedcharraw_data[100]; octet1.set_data(raw_data,100);//setthedataofantounsignedchardata //getthevalidityofanOctetStr cout<<(octet1.valid())?“Octet1isvalid”:“Octet1isInvalid”; };//endoctetexample |
SNMP++之TimeTicksClass的对象模型(ObjectModelingTechnique)视图
SNMP++的TimeTicksClass为使用SMI中的timeticks带来了方便。SMI的时间戳被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMItimeticks被加工成了一种特殊的类型。因此SNMP++的TimeTicks类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到TimeTicks的对象上一样有效。TimeTicksclass与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,TimeTicks的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMItimeticks,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。
9.2.TimeTicksClass的成员函数列表
TimeTicksClassMemberFunctions |
说明 |
Constructors |
|
TimeTicks::TimeTicks(void); |
构造一个空的TimeTicks对象 |
TimeTicks::TimeTicks(constunsignedlongi); |
用一个无符号长整形来构造一个TimeTicks对象 |
TimeTicks:;TimeTicks(constTimeTicks&t); |
用一个已有的TimeTicks对象来构造一个新的 |
Destructor |
|
TimeTicks::~TimeTicks(); |
销毁一个TimeTicks对象 |
OverloadedOperators |
|
TimeTicks&operator=(constTimeTicks&t); |
重载赋值操作符 |
char*get_printable(); |
格式化输出,格式为:DDDays,HH:MM:SS.hh |
operatorunsignedlong(); |
把TimeTicks转换为无符号长整形 |
TimeTicks对象用TimeTicks::get_printable()输出时,其值自动被格式化为“DDdays,HH:MM:SS.hh”。其中DD代表天,HH代表小时(24时制的),MM代表分钟,SS是秒钟,hh则是百分之几秒。
//TimeTicksExamples
#include“timetick.h”
voidtimeticks_example()
{
TimeTickstt;//createanun-initializedtimeticksinstance
TimeTickstt1((unsignedlong)57);//createatimeticksusinganumber
TimeTickstt2(tt1);//createatimeticksusinganotherinstance
tt=192;//overloadedassignmenttoanumber
tt2=tt;//overloadedassignmenttoanothertimeticks
cout<<tt.get_printable();//printoutinDDdays,HH:MM:SS.hh
cout<<(unsignedlong)tt;//printoutunsignedlongintvalue
};//endtimeticksexample
SNMP++之Counter32Class的对象模型(ObjectModelingTechnique)视图
当需要用到SMI中的32位计数器时,SNMP++的Counter32Class为之带来了方便。SMI的计数器被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMIcounters被加工成了一种特殊的类型。因此SNMP++的Counter32类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到Counter32的对象上一样有效。Counter32class与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,Counter32的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMIcounter,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。
10.2.Counter32Class的成员函数列表
Counter32ClassMemberFunctions |
说明 |
Constructors |
|
Counter32::Counter32(void); |
构造一个空的Counter32对象 |
Counter32::Counter32(constunsignedlongi); |
用一个无符号长整形来构造一个Counter32对象 |
Counter32::Counter32(constCounter32&c); |
用一个已有的Counter32对象来构造一个新的 |
Destructor |
|
Counter32::~Counter32(); |
销毁一个TimeTicks对象 |
OverloadedOperators |
|
Counter32&operator=(constCounter32&c); |
重载赋值操作符 |
char*get_printable(); |
格式化输出Counter32对象 |
operatorunsignedlong(); |
把Counter32转换为无符号长整形 |
//CounterExamples
#include“counter.h”
voidcounter_example()
{
Counter32ctr;//createanun-initializedcounterinstance
Counter32ctr1((unsignedlong)57);//createacounterusinganumber
Counter32ctr2(ctr1);//createacounterusinganotherinstance
ctr=192;//overloadedassignmenttoanumber
ctr1=ctr;//overloadedassignmenttoanothercounter
cout<<(unsignedlong)ctr;//behavelikeanunsignedlongint
};//endcounterexample
SNMP++之Gauge32Class的对象模型(ObjectModelingTechnique)视图
SNMP++的Gauge32Class为使用SMI中的timeticks带来了方便。SMI的容量被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMIgauges被加工成了一种特殊的类型。因此SNMP++的Gauge32类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到Gauge32的对象上一样有效。Gauge32class与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,TimeTicks的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMIgauge,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。
11.2.Gauge32Class的成员函数列表
Gauge32ClassMemberFunctions |
说明 |
Constructors |
|
Gauge32::Gauge32(void); |
构造一个空的Gauge32对象 |
Gauge32::Gauge32(constunsignedlongi); |
用一个无符号长整形来构造一个Gauge32对象 |
Gauge32::Gauge32(constGauge32&g); |
用一个已有的Gauge32对象来构造一个新的 |
Destructor |
|
Gauge32::Gauge32(); |
销毁一个Gauge32对象 |
OverloadedOperators |
|
Gauge32&operator=(constGauge32&g); |
重载赋值操作符 |
char*get_printable(); |
格式化输出Gauge32对象 |
operatorunsignedlong(); |
把Gauge32转换为无符号长整形 |
//GaugeExamples
#include“gauge.h”
voidgauge_example()
{
Gauge32gge;//createanun-initializedGaugeinstance
Gauge32gge1((unsignedlong)57);//createaGaugeusinganumber
Gauge32ctr2(ctr1);//createaGaugeusinganotherinstance
gge=192;//overloadedassignmenttoanumber
gge1=gge;//overloadedassignmenttoanothercounter
cout<<(unsignedlong)gge;//behavelikeanunsignedlongint
};//endgaugeexample
SNMP++之Counter64Class的对象模型(ObjectModelingTechnique)视图
SNMP++的64bitcounterclass实现了SMI的64bitcounters。64位计数器是在SNMPv2中定义的一种变量,所以在SNMPv1中并不存在这种MIB变量。64bitcounters由两个无符号长整形(一高位、一低位)组成,Counter64class很好的实现了它。因为Counter64class提供了加减乘除操作符的重载,所以它使用起来感觉很自然。
12.2.Counter64Class的成员函数列表
Counter64ClassMemberFunctions |
说明 |
Constructors |
|
Counter64::Counter64(void); |
构造一个空的Counter64对象 |
Counter64::Counter64(constunsignedlonghi,constunsignedlonglow); |
用两个无符号长整形来构造一个Counter64对象 |
Counter64::Counter64(constCounter64&ctr64); |
拷贝构造函数 |
Counter64::Counter64(constunsignedlongul); |
用一个无符号长整形来构造一个Counter64对象 |
Destructor |
|
Counter64::~Counter64(); |
销毁一个Counter64对象 |
OverloadedOperators |
|
Counter64&operator=(constCounter64&ctr64); |
将一个Counter64对象付给另一个 |
Counter64&operator=(constunsignedlongi); |
用一个无符号长整形设置Counter64对象的低位,同时清除了它的高位 |
Counter64operator+(constCounter64&ctr64); |
两个Counter64对象相加 |
Counter64operator-(constCounter64&ctr64); |
两个Counter64对象相减 |
Counter64operator*(constCounter64&ctr64); |
两个Counter64对象相乘 |
Counter64operator/(constCounter64&ctr64); |
两个Counter64对象相除 |
intoperator==(Counter64&lhs,Counter64&rhs); |
判断两个Counter64对象是否相等 |
intoperator!=(Counter64&lhs,Counter64&rhs); |
判断两个Counter64对象是否不相等 |
intoperator<(Counter64&lhs,Counter64&rhs); |
判断一个Counter64是否比另一个小 |
intoperator<=(Counter64&lhs,Counter64&rhs); |
判断一个Counter64是否“小于等于”另一个 |
intoperator>(Counter64&lhs,Counter64&rhs); |
判断一个Counter64是否比另一个大 |
intoperator>=(Counter64&lhs,Counter64&rhs); |
判断一个Counter64是否“大于等于”另一个 |
MemberFunctions |
|
unsignedlonghigh(); |
返回Counter64对象的高位 |
unsignedlonglow(); |
返回Counter64对象的低位 |
voidset_high(); |
设置Counter64对象的高位 |
voidset_low(); |
设置Counter64对象的低位 |
//Counter64examples
#include“ctr64.h”
voidcounter64_example()
{
Counter64c64;//instantiatea64bitcounterobjectwithnoparms
Counter64my_c64(100,100);//instantiatea64bitcounterwithahiandlowvalue
Counter64your_c64(my_c64);//instantiatea64counterusinganother64bitcounter
cout<<my_c64.high();//printoutthehighportionofthec64
cout<<my_c64.low();//printoutthelowportionofthec64
c64=my_c64+your_c64;//overloadedaddition
c64=my_c64*your_c64;//overloadedmultiplication
c64=my_c64/your_c64;//overloadeddivision
c64=my_c64-your_c64;//overloadedsubtraction
if(c64==my_c64)//overloadedequivalencetest
cout<<“c64equalsmy_c64\n”;
if(c64!=my_c64)//overloadednotequaltest
cout<<“c64notequaltomy_c64\n”;
if(c64<my_c64)//overloadedlessthan
cout<<“c64lessthanmy_c64\n”;
};//endCounter64example
SNMP++之AddressClass的对象模型(ObjectModelingTechnique)视图
网络地址类是一组C++类的集合,它提供了简单、安全、可移植、高效地使用网络地址的方法。许多网络管理应用需要通过网络地址来访问和管理设备,包括地址的确认、更改,以及用户接口的分配。Addressclass不但管理了所有指定的网络地址的内部细节,而且还通过封装和隐藏其内部机制,让得到解放的开发应用的程序员可以专注于解决实际问题。开发Addressclass的动机来源于95年InteropSNMP++Birds-of-A-Feather(BOF)上的讨论以及与Hewlett-PackardOpenView程序员的交流。
地址类提供了以下好处:自动内存管理、地址确认、移植到任何C++环境、简单易用,及可扩充性。目前的Addressclass由4个子类组成:IpAddressClass,IpxAddressClass,MacAddressclass和GenAddressclass。将来也许会有其他的子类加入,比如IPNextGeneration(IPng)。
所有地址类都派生自同一个抽象基类:Addressclass。它是一个抽象类,即这个类不会产生实例对象。Addressclass通过使用虚成员函数,提供了公用接口。也就是说可以使用公用接口调用各个不同地址类的函数。这样的结果是:当需要修改使用了地址类的模块时,需要改动的代码就很少了。
作为基类的AddressClasses是一个抽象类,它囊括了所有子类的通用操作。也即包含了以下统一的接口:构造、访问、修改地址。
AddressClassMemberFunctions |
说明 |
IpAddressClassConstructors |
|
IpAddress::IpAddress(void); |
构造一个空的IpAddress对象 |
IpAddress::IpAddress(constchar*string); |
用一个字符串构造一个IpAddress,当需要时一般用到DNS上 |
IpAddress::IpAddress(constIpAddress&ipa); |
拷贝构造函数 |
IPAddressMemberFunctions |
|
char*friendly_name(int&status); |
让DNS的名字看起来更友好 |
UdpAddressConstructors |
|
UdpAddress::UdpAddress(void); |
构造一个无效的UdpAddress对象 |
UdpAddress::UdpAddress(constchar*string); |
用一个字符串构造一个UdpAddress |
UdpAddress::UdpAddress(constUdpAddress&udpa); |
用一个已有的UdpAddress来构造另一个 |
UdpAddressMemberFunctions |
|
voidUdpAddress:set_port(constunsignedintp); |
设置UdpAddress对象的端口号 |
unsignedintUdpAddress::get_port(); |
获取UdpAddress对象的端口号 |
IpxAddressClassConstructors |
|
IpxAddress::IpxAddress(void); |
构造一个空的IPX地址 |
IpxAddress::IpxAddress(constchar*string); |
用一个字符串构造一个IPX地址 |
IpxAddress::IpxAddress(constIpxAddress&ipxa); |
拷贝构造函数 |
IpxSockAddressConstuctors |
|
IpxSockAddress::IpxSockAddress(void); |
构造一个空的IpxSockAddress对象 |
IpxSockAddress::IpxSockAddress(constchar*string); |
用一个字符串构造一个IpxSockAddress |
IpxSockAddress::IpxSockAddress(constIpxSockAddress&ipxs); |
用一个已有的IpxSockAddress来构造另一个 |
IpxSockAddressMemberFunctions |
|
IpxSockAddress::set_socket(constunsignedints); |
从一个IpxSockAddress获得套接字 |
unsignedintIpxSocketAddress::get_socket(); |
设置一个IpxSockAddress的套接字 |
MacAddressConstructors |
|
MacAddress::MacAddress(void); |
构造一个空的MacAddress对象 |
MacAddress::MacAddress(constchar*string); |
用一个字符串构造一个MacAddress |
MacAddress::MacAddress(constMacAddress&mac); |
拷贝构造函数 |
GenAddressConstructors |
|
GenAddress::GenAddress(void); |
构造一个无效的GenAddress对象 |
GenAddress::GenAddress(constchar*addr); |
用一个字符串构造一个GenAddress |
GenAddress::GenAddress(constGenAddress&addr); |
拷贝构造函数 |
CommonMemberFunctions,applicabletoallAddressclasses |
|
intoperator==(constAddress&lhs,constAddressrhs); |
判断两个地址是否相等 |
intoperator!=(constAddress&lhs,constAddress&rhs); |
判断两个地址是否不相等 |
intoperator>(constAddress&lhs,constAddress&rhs); |
判断一个地址是否大于另一个 |
intoperator>=(constAddress&lhs,constAddress&rhs); |
判断一个地址是否大于等于另一个 |
intoperator<(constAddress&lhs,constAddress&rhs); |
判断一个地址是否小于另一个 |
intoperator<=(constAddress&lhs,constAddress&rhs); |
判断一个地址是否小于等于另一个 |
intoperator==(constAddress&lhs,cosntchar*inaddr); |
判断一个地址是否等于一个字符串 |
intoperator>(constAddress&lhs,constchar*inaddr); |
判断一个地址是否大于一个字符串 |
intoperator<(constAddress&lhs,constchar*inaddr); |
判断一个地址是否小于一个字符串 |
virtualintvalid(); |
判断一个地址的有效性 |
unsignedchar&operator[](intposition); |
允许通过数组的下标操作符来访问一个地址 |
char*get_printable(); |
返回格式化输出的地址 |
IpAddressClass可以通过调用成员函数Address::get_printable()自动以DNS显示出来。如果没有激活DNS或者无法识别地址,则返回以点号分割的字符。另一方面,一个IpAddress可以用一个友好的名字(字符串,而非以点号分割的数字)来构造,这样构造函数就可以激活DNS的显示。如果这个名字没被找到,那么该地址也就是无效的。这个强大的功能允许你在对外表现时,使用友好的名字方式。
GenAddressclass允许创建和使用通用的地址,即GenAddress拥有其他地址类(IpAddress,IpxAddress和MacAddress)的操作和属性,所以你可以使用GenAddress来操作任何地址。GenAddressclass的构造函数允许用任何字符串来建立一个地址。构造函数通过匹配的字符串以及加载在GenAddress上的属性与操作,决定其地址的具体类型。这样就解放了程序员,因为面对不一样的地址,程序员不用再专门写代码来处理了。
GenAddressExamples
GenAddressaddress1(“10.4.8.5”);//makeanIPGenAddress
GenAddressaddress2(“01020304-10111213141516”);//makeanIPXGenAddress
GenAddressaddress3(“01:02:03:04:05:06”);//makeaMACGenAddress
cout<<address3.get_printable();//printouttheGenAddress
if(!address1.valid())//checkvalidity
cout<<“address1!valid”;
所有地址类都支持成员函数::valid(),它可以返回指定地址对象的有效性。有效性是在构造或给一个地址对象赋值时决定的。只有在赋值之后,成员函数::valid()才可以被用来判断其有效性。
AddressClassValidationExamples
MacAddressmac;
mac=“01.010a0d”;//invalidMACaddress
printf(“%s”,(mac.valid()?“Valid”:”Invalid”));
13.8.UdpAddresses和IpxSockAddresses
大多数时候,SNMP++的用户会使用默认的端口号和套接字来进行SNMP操作。就IP协议而言,161端口一般用来作为代理的目标端口,162端口一般用作trap和Notification的接收端口。有些时候需要改变指定的端口号和套接字,UdpAddressclass和IpxSockAddressclass就允许定义端口和套接字的信息。
当向一个使用非标准默认端口的代理端发送请求信息时,就需要用到UdpAddressesclass了。UdpAddressesclass提供了两个成员函数分别来设置和获取自定义的端口信息。用一个加载了UdpAddresses的目标来发送请求,就可以实现SNMP++对自定义端口的使用。
当向一个使用非标准默认IPX套接字的代理端发送请求信息时,就需要用到IpxSockAddressesclass了。IpxSockAddresses提供了两个成员函数分别来设置和获取自定义的IPX套接字信息。用一个加载了IpxSockAddress的目标来发送请求,就可以实现SNMP++对自定义套接字的使用。
13.8.3.用UdpAddress和IpxSockAddress接收Notification
UdpAddress和IpxSockAddress还可以通过指定需要修改的端口和套接字来接收notification。即允许应用通过非标准的端口和套接字来接收trap和inform。
目前的有效地址格式定义如下:
ValidIPformatBNFGrammarXXX.XXX.XXX.XXX
ip-address:ip-tokenDOTip-tokenDOTip-tokenDOTip-token
DOT:‘.’
ip-token:[0-255]
ValidIPXformatBNFGrammarXXXXXXXX:XXXXXXXXXXXX
ipx-address:net-idSEPARATORmac-id
SEPARATOR:‘‘|‘:’|‘-’|‘.’
net_id:1{byte-token}4
mac-id:1{byte-token}6
byte-token:1{byte}2
byte:[0-9|a-f|A-F]
ValidMACformatBNFGrammarXX:XX:XX:XX:XX:XX
mac-id:byte_tokencolonbyte_tokencolonbyte_tokencolonbyte_tokencolonbyte_token
byte-token:1{byte}2
byte:[0-9|a-f|A-F]
colon:‘:’
//addressclassexamples
#include“address.h”
voidaddress_examples()
{
//--------------[IPAddressconstruction]------------------------------------------------------
IpAddressip1();//makesaninvalidIpAddressobject
IpAddressip2(“10.4.8.5”);//makesaIpAddressverifiesdottedformat
IpAddressip3(ip2);//makesanIpAddressusinganotherIpAddress
IpAddressip4(“trout.rose.hp.com”);//makesanIpAddressdoesDNSonstring
//-------------[IPXAddressconstruction]-----------------------------------------------------
IpxAddressipx1();//makesaninvalidIPXaddress
IpxAddressipx2(”);//makesandverifiesanIPXaddress
IpxAddressipx3(ipx2);//makesanIPXfromanotherIPX
//--------------[MACAddressconstruction]-----------------------------------------------------
MacAddressmac1();//makesaninvalidMACaddress
MacAddressmac2(“08:09:12:34:52:12”);//makesandverifiesaMACaddress
MacAddressmac3(mac2);//makesaMACfromanotherMAC
//---------------[GenAddressConstruction]-----------------------------------------------------
GenAddressaddr1(“10.4.8.5”);
GenAddressaddr2(“01020304:050607080900”);
//--------------[printingaddresses]----------------------------------------------------------------
cout<<(char*)ip2;
cout<<(char*)ipx2;
cout<<(char*)mac2;
//---------------[assigningAddresses]------------------------------------------------------------
ip1=“15.29.33.10”;
ipx1=“00000001-080912345212”;
mac1=“08:09:12:34:52:12”;
//--------------[comparingAddresses]----------------------------------------------------------
if(ip1==ip2)
cout<<“ip1==ip2”;
if(ipx1!=ipx2)
cout<<“ipx1!=ipx2”;
if(mac1<=mac2)
cout<<“mac1<mac2”;
//---------------[modifyinganaddress]-----------------------------------------------------------
mac1[4]=15;
cout<<mac2[2];
};//endaddressexamples
SNMP++之VariableBinding(Vb)Class的对象模型(ObjectModelingTechnique)视图
VariableBinding(Vb)class是SNMP“绑定变量”的封装。一个“绑定变量”是由SNMP的objectID及其SMI的value组合而成的。用面向对象的概念来看,这只是一个简单的关联关系:一个Vb对象含有一个Oid对象及其SMI的value。Vbclass允许应用的开发者实例化Vb对象,然后为其分配Oid部分(用Vb::set_value()),并分配value部分(用Vb::get_value())。相反的,Oid和value部分可以通过成员函数Vb::get_oid()和Vb::get_value()提取出来。通过重载了的公有成员函数Vb::set_value()和Vb::get_value(),可以把不同的SMI的value针对“绑定变量”进行“设置”与“取出”。“绑定变量表”在SNMP++中表现为Vb对象的数组。所有的SMI类型都与VbClass兼容。Vbclass隐藏了所有内部数据。使用者不需要知道SMI的value的类型,Oid的内部表示方法,以及其他SNMP相关的结构。如果使用的是标准ANSIC++编译器,Vbclass是完全可移植的。
14.1.VariableBindingClass成员函数列表
VariableBindingClassMemberFunctions |
说明 |
Constructors |
|
Vb(void); |
构造一个空的Vb对象 |
Vb(constOid&oid); |
用Oid部分构造一个Vb |
Vb(constVb&vb); |
拷贝构造函数 |
Destructor |
|
~Vb(); |
销毁一个Vb,释放所有的资源 |
SetOid/GetOid |
|
voidset_oid(constOid&oid); |
设置一个Vb的Oid部分 |
voidget_oid(Oid&oid)const; |
获得Oid部分 |
SetValue |
|
voidset_value(constSMIValue&val); |
设置任一SmiValue |
voidset_value(constinti); |
设置一整形value |
voidset_value(constlonginti); |
设置一长整形value |
voidset_value(constunsignedlonginti); |
设置一无符号长整形value |
voidset_value(constcharWINFAR*ptr); |
设置一有结束标志符的字符串value |
GetValue |
|
intget_value(SMIValue&val); |
获得任一SmiValue |
intget_value(int&i); |
获得一整形value |
intget_value(longint&i); |
获得一长整形value |
intget_value(unsignedlongint&i); |
获得一无符号长整形value |
intget_value(unsignedcharWINFAR*ptr, unsignedlong&len); |
获得一无符号字符数组,返回数据及其长度 |
intget_value(unsignedcharWINFAR*ptr, unsignedlong&len, unsignedlongmaxlen); |
获得一指定长度的无符号字符数组,指定长度不超过最大长度。 |
intget_value(charWINFAR*ptr); |
获得一有结束标志符的字符串 |
Miscellaneous |
|
SmiUINT32get_Syntax(); |
返回SMI描述 |
char*get_printable_value(); |
返回格式化value |
char*get_printable_oid(); |
返回格式化Oid部分 |
voidset_null(); |
给Vb对象设置一个空value |
intvalid(); |
返回一个Vb的有效性 |
OverloadedOperators |
|
Vb&operator=(constVb&vb); |
把一个Vb付给另一个 |
14.2.VbClass的公有成员函数
//AVbobjectmaybeconstructedwithnoarguments.Inthiscase,theOidand
//valueportionsmustbesetwithsubsequentmemberfunctioncalls.
//constructorwithnoarguments
//makesanVb,un-initialized
Vb::Vb(void);
14.2.1.VbClass的构造和析构函数
Vb对象可以用一个Oid对象作为构造函数的参数来构造,即把Vb对象的Oid部分初始化为以参数方式传进来的Oid。Vb对象生成了一个传进来的Oid的拷贝,所以程序员不用担心Oid参数的执行期问题。
//constructortoinitializetheOid
//makesaVbwithOidportioninitialized
Vb::Vb(constOidoid);
Vb对象的析构函数释放了所有占用过的内存和资源。对于定义的静态对象,析构函数是在对象作用域结束时自动调用的。动态分配的实例对象需要用delete来析构。
//destructor
//iftheVbhasaOidoranoctetstringthen
//theassociatedmemoryneedstobefreed
Vb::~Vb();
14.2.2.VbClass的GetOid/SetOid成员函数
成员函数GetOid/SetOid允许获取/设置Vb对象的Oid部分。当SNMP发出gets或者sets操作的时候,变量的指定是通过Vb::set_oid(Oidoid).设置Vb的Oid值来的。相反,Oid部分可以通过成员函数Vb::get_oid(Oid&oid)来获取。成员函数get_oid在SNMP的getnext操作中的非常有用。
Vb对象的Oid部分可以用一个已存在的Oid对象来设置
//setvalueOidonlywithanotherOid
voidVb::set_oid(constOid&oid);
Oid部分可以通过提供一个目标Oid对象来检索。这将销毁原先的Oid对象的值。
//getOidportion
voidVb::get_oid(Oid&oid);
14.2.3.VbClass的GetValue/SetValue成员函数
成员函数get_value,set_value允许获取或设置Vb对象的value部分。这些成员函数通过重载支持对不同类型的获取和设置。隐藏了获取或设置Vb的内部机制,管理了所有内存的分配和释放。这样,程序员就不用担心SMI-value的结构以及它们的管理。通常在SNMP执行了get后,用成员函数getvalue来获取Vb对象的value。如果希望在SNMP执行set操作时设置Vb的value的话,成员函数setvalue就有用了。如果获取的value与Vb所包含的不匹配,则成员函数get_value返回-1。
向Vb对象设置一整形value,作为SMIINT的映射。
//setthevaluewithanint
voidVb::set_value(constinti);
向Vb对象设置一长整形value,作为SMIINT32的映射。
//setthevaluewithalongsignedint
voidVb::set_value(constlonginti);
向Vb对象设置一无符号长整形value,作为SMIUNIT32的映射。
//setthevaluewithanunsignedlongint
voidVb::set_value(constunsignedlonginti);
向Vb对象设置一Gauge32对象作为value,该value是SMI32bit的映射。
//setthevaluewitha32bitgauge
voidVb::set_value(constGauge32gauge);
向Vb对象设置一TimeTicks对象作为value,该value是SMItimeticks的映射。
//setthevaluewithaTimeTicks
voidVb::set_value(constTimeTickstimeticks);
向Vb对象设置一Counter32对象作为value,该value是SMI32bitcounter的映射。
//setvaluewitha32bitcounter
voidVb::set_value(constCounter32counter);
向Vb对象设置一Counter64对象作为value,该value用以构成SMI64bitcounter的32bit的高位部分与低位部分。
//setvaluetoa64bitcounter
voidVb::set_value(constCounter64c64);
用一个Oid设置Vb对象的value部分。
//setvalueforsettinganOid
//createsownspaceforanOidwhich
//needstobefreedwhendestroyed
voidVb::set_value(constOid&varoid);
用一个char型的字符串设置一个Vb对象的value部分。事实上,这在内部是用8位字符串作为SMI的value部分,但是当它是一个ASCII字符串(比如系统标识符)时,这种表示却会显得更简单。
//setvalueonastring
//makesthestringanoctet
//thismustbeanullterminatesstring
voidVb::set_value(constchar*ptr);
用一个IPaddress对象设置Vb的value部分。该成员函数使用了Addressclass。IPaddress是SMIvalue类型的一种。
//setanIPAddressobjectasavalue
voidVb::set_value(constIpAddressipaddr);
用一个IPXaddress对象设置Vb的value部分。该成员函数使用了Addressclass。IPXaddress是8位SMIvalue类型的一种。
//setanIPXaddressobjectasavalue
voidVb::set_value(constIpxAddressipxaddr);
用一个MACaddress对象设置Vb的value部分。该成员函数使用了Addressclass。MACaddress是8位SMIvalue类型的一种。
//setanMACaddressobjectasavalue
voidVb::set_value(constMacAddressmacaddr);
//setanGenAddressobjectasavalue
voidVb::set_value(constGenAddressgenaddr);
//setanUdpAddressobjectasavalue
voidVb::set_value(constUdpAddressudpaddr);
14.2.6.用一个IpxSockAdress对象设置value
//setanIpxSockAddressobjectasavalue
voidVb::set_value(constIpxSockAddressipxsockaddr);
//setthevalueportiontoaSNMP++Octetobject
voidVb::set_value(constOctetStroctet);
14.2.8.VbClass成员函数:GetValue
所有的成员函数Vb::get_value都会修改传进来的参数。如果一个Vb对象不包含被请求的参数类型,该参数不会被修改,并且将返回SNMP_CLASS_INVALID。否则,如果成功将会返回SNMP_CLASS_SUCCESS的状态。
从Vb对象获得一个整形value
//getvalueint
//returns0onsuccessandvalue
intVb::get_value(int&i);
从Vb对象获得一个长整形value
//getthesignedlongint
intVb::get_value(longint&i);
从Vb对象获得一个无符号长整形value
//gettheunsignedlongint
intVb::get_value(unsignedlongint&i);
//getaGauge32 intVb::get_value(Gauge32&gauge); |
从Vb对象获得一个Gauge32
从Vb对象获得一个TimeTicks
//getaTimeTicksfromaVb
intVb:get_value(TimeTicks&timeticks);
从Vb对象获得一个Counter32
//getacounterfromaVb
intVb::get_value(Counter32&counter);
从Vb对象获得一个64bitcounter
//geta64bitcounter
intVb::get_value(Counter64&counter64);
从Vb对象获得一个Oid对象
//gettheOidvalue
//freetheexistingOidvalue
//copyinthenewOidvalue
intVb::get_value(Oid&varoid);
从Vb对象获得一个无符号char型字符串(Octetstring)
//getaunsignedcharstringvalue
//destructive,copiesintogivenptrofup
//tolenlength
intVb::get_value(unsignedchar*ptr,unsignedlong&len);
从Vb对象获得一个char型字符串。该操作获得octetstring部分,并在其后加一空值。
//getachar*fromanoctetstring
//theusermustprovidespaceor
//memorywillbesteppedon
intVb::get_value(char*ptr);
从Vb对象获得一个IPaddress对象。IPaddress是一种Address对象。
//getanIPAddress
intVb::get_value(IpAddress&ipaddr);
从Vb对象获得一个IPXAddress对象。IpxAddress是一种Address对象。
//getanIPXAddress
intVb::get_value(IpxAddress&ipxaddr);
从Vb对象获得一个MACAddress对象。MacAddress是一种Address对象。
//getanMACaddress
intVb::get_value(MacAddress&MACaddr);
从Vb对象获得一个GenAddress对象。GenAddress是一种Address对象。
//getangenaddress
intVb::get_value(GenAddress&genaddr);
从Vb对象获得一个UdpAddress对象。UdpAddress是一种Address对象
//getanUdpaddress
intVb::get_value(UdpAddress&Udpaddr);
从Vb对象获得一个IpxSockAddress对象。IpxSockAddress是一种Address对象
//getanIpxSockAddress
intVb::get_value(IpxSockAddress&IpxSockAddr);
从Vb对象获得一个Octet对象
//getanOctetobjectfromaVb
intVb::get_value(OctetStr,&octet);
该函数并未遵循面向对象规则。如果要知道对象代表的事物,可以通过该函数返回对象内部的id,但同时也破坏了内部数据的隐藏。如果不考虑数据隐藏的话,有些时候可能还是需要知道Vb内部的value,以便抽取出那些隐藏的value。比如,当实现一个浏览器时需要获取Vb,询问Vb有什么数据并取出Vb包含的数据。该操作所返回的Syntaxvalues就是SMISyntaxvalue。
//returnthecurrentSyntax
//ThismethodviolatestheOOparadigmbutmaybeusefulif
//thecallerhasaVbobjectanddoesnotknowwhatitis.
//Thiswouldbeusefulintheimplementationofabrowser.
SmiUINT32get_Syntax();
通过调用成员函数Vb::valid()可以检查一个Vb对象的实例的有效性。有效的Vb是那些已经获得了Oid的。
//determineifaVbobjectisvalid
intVb::valid();
通过重载赋值操作符“=”,Vb对象可以相互赋值。这种简单的相互赋值避免以下操作:查询一个Vb对象的内容,然后手工将其赋给另一个目标Vb对象。
//overloadedVbassignment
//assignmenttoanotherVbobjectoverloaded
Vb&operator=(const&Vbvb);
14.2.12.Vb对象的错误信息
当用Vb::get_value()从一个Vb对象获取数据时,由于Vb数据类型与你所请求的数据类型的不一致将导致一个错误的出现。例如,假设一个Vb对象有一个OctetStr对象,你却要求提取TimeTicks对象。由于无法返回TimeTicks,Vb::get_value()会失败。当错误事件发生时,相应的调用模块使用Vb::get_Syntax()来询问Vb的实际值或者错误值。
Vb::get_value()returnvalue |
说明 |
SNMP_CLASS_SUCCESS |
成功,返回所请求的值 |
SNMP_CLASS_INVALID |
失败,Vbvalue没有包含请求的值 |
下面的例子展示了使用Vbclass的不同方法。除了Oidclass,Vbclass不需要依赖于其他库或模块。以下C++代码是ANSI兼容的。
#include“oid.h”
#include“vb.h”
vb_test()
{
//-------[WaystoconstructVbobjects]-------
//constructasingleVbobject
Vbvb1;
//constructaVbobjectwithanOidobject
//thissetstheOidportionoftheVb
Oidd1(“1.3.6.1.4.12”);
Vbvb2(d1);
//constructaVbobjectwithadottedstring
Vbvb3((Oid)“1.2.3.4.5.6”);
//constructanarrayoftenVbs
Vbvbs[10];
//------[WaystosetandgettheOidportionofVbobjects]
//setandgettheOidportion
Oidd2((Oid)“1.2.3.4.5.6”);
vb1.set_oid(d2);
Oidd3;
vb1.get_oid(d3);
if(d2==d3)cout<<“Theybetterbeequal!!\n”;
Vbten_vbs[10];
intz;
for(z=0;z<10;z++)
ten_vbs[0].set_oid((Oid)“1.2.3.4.5”);
//-------[waystosetandgetvalues]
//set&getints
intx,y;
x=5;
vb1.set_value(x);
vb1.get_value(y);
if(x==y)cout<<“xequalsy\n”;
//setandgetlongints
longinta,b;
a=100;
//-------[waystosetandgetvalues]
if(a==b)cout<<“aequalsb\n”;
//set&getunsignedlongints
unsignedlongintc,d;
c=1000;
vbs[0].set_value(c);vbs[0].get_value(d);
if(c==d)cout<<“cequalsd\n”;
//seta64bitcounter
Counter64c64(1000,1001);
vbs[1].set_value(c64);
//getandsetanoidasavalue
Oido1,o2;
o1=“1.2.3.4.5.6”;
vbs[2].set_value(o1);vbs[2].get_value(o2);
if(o1==o2)cout<<“o1equalso2\n”;
//setandgetanoctetstring
unsignedchardata[4],outdata[4];
unsignedlonglen,outlen;
len=4;data[0]=10;data[1]=12;data[2]=12;data[3]=13;
OctetStroctetstr(data,len);
vbs[3].set_value(octetstr);
vbs[3].get_value(octetstr);
//get&setastring
charbeer[80];chargood_beer[80];
strcpy(beer,”SierraNevadaPaleAle”);
vbs[4].set_value(beer);
vbs[4].get_value(good_beer);
printf(“GoodBeer=%s\n”,good_beer);
//getandsetanipanaddress
IpAddressipaddress1,ipaddress2;
ipaddress1=“10.4.8.5”;
vbs[5].set_value(ipaddress1);
vbs[5].get_value(ipaddress2);
cout<<ipaddress2;
}//endvbexample
SNMP++之PduClass的对象模型(ObjectModelingTechnique)视图
SNMP++的Pduclass是SMIProtocolDataUnit(PDU)的C++封装。PDU是管理端和代理端进行SNMP通讯的基本概念。通过Pduclass,SNMP++使得对PDU的操作变得简单、安全。Pduclass允许简单的构造、析构,以及在Pdu对象上加载、卸载Vb对象。因为SNMP++是双效的API,所以Pduclass也是抽象化的,并没有包含SNMPv1或者SNMPv2的特征性的信息。所有发出请求的Snmpclass成员函数都可以只使用一个Pdu对象。Pduclass作为Snmpclass的接口,处理SNMP请求,同时还可作为异步请求和接收notification的回调函数的参数。注意,关于对Vb的存储,Pdu对象是从0开始的(Pdu中第一个vb是Vb#0)。
大多数地方,SNMP++中的所有Pdu对象都是一样的。即,所有的Pdu对象都有同一性(identity)。唯一的例外是当Pdu对象被用作发送otifications,traps和informs的时候。为了支持notifications,有3个附加的PduClass成员函数来用作:设置同一性(identity)、时间信息,及Pdu对象的enterprise。
15.1.PduClass成员函数列表
PduClassMemberFunctions |
说明 |
Constructors |
|
Pdu::Pdu(void); |
构造一个空的Pdu |
Pdu::Pdu(Vb*pvbs,constintpvb_count); |
用一个数组类型的Vb及其长度构造一个Pdu |
Pdu::Pdu(constPdu&pdu); |
用一个Pdu构造另一个 |
MemberFunctions |
|
intget_vblist(Vb*pvbs,constintpvb_count); |
把Vb拷贝到调用的参数列表中(vblist) |
intset_vblist(Vb*pvbs,constintpvb_count); |
设置Pdu调用的参数列表中的Vb |
intget_vb(Vb&vb,constintindex); |
获取Pdu中一个指定的Vb |
intset_vb(Vb&vb,constintindex); |
为Pdu设置一个指定的Vb |
intget_vb_count(); |
获取Pdu中Vb的个数 |
intget_error_status(); |
|
intget_error_index(); |
|
unsignedlongget_request_id(); |
获取Pdu的请求标示 |
unsignedshortget_type(); |
获取Pdu的类型 |
intvalid(); |
判断Pdu的有效性 |
Intdelete_vb(constintposition); |
删除Pdu指定位置上的Vb |
inttrim(constinti=1); |
|
MemberFunctionsForInformandTrapUsage |
|
voidset_notify_timestamp(constTimeTicks×tamp); |
为trap或inform的Pdu设置时间信息 |
voidget_notify_timestamp(TimeTicks×tamp); |
从trap或inform的Pdu获取时间信息 |
voidset_notify_id(constOidid); |
设置trap或inform的Pdu的ID |
voidget_notify_id(Oid&id); |
获取trap或inform的Pdu的ID |
voidset_notify_enterprise(constOid&enterprise); |
设置trap或inform的Pdu的enterpriseID |
voidget_notify_enterprise(Oid&enterprise); |
获取trap或inform的Pdu的enterpriseID |
OverloadedOperators重载操作符 |
|
Pdu&operator=(constPdu&pdu); |
将一个Pdu付给另一个 |
Pdu&operator+=(Vb&vb); |
给一个Pdu增加一个Vb |
有多种方法构造Pdu对象,可以有也可以没有构造参数
//constructor,noargs
Pdu::Pdu(void);
//constructorwithVbsandcount
Pdu::Pdu(Vb*vbs,constintvb_count);
//constructorwithanotherPduinstance
Pdu::Pdu(constPdu&pdu);
//destructor
Pdu::~Pdu();
15.3.访问Pdu的成员函数
Pduclass通过多种成员函数来支持获取和设置Pdu成员变量。包括获取和设置“绑定变量”、错误信息、请求信息,和类型信息。
//extractalltheVbsfromaPdu
intPdu::get_vblist(Vb*vbs,constintvb_count);
//depositVbstoaPdu
intPdu::set_vblist(Vb*vbs,constintvb_count);
//getaparticularvb
//whereindex0isthe1stvb
intPdu::get_vb(Vb&vb,constintindex);
//setaparticularVb
//whereindex0isthe1stVb
intPdu::set_vb(Vb&vb,constintindex);
//returnthenumberofVbs
intPdu::get_vb_count();
//returntheerrorindex
intPdu::get_error_index();
//gettheerrorstatus
intPdu::get_error_status();
//returntherequestid
unsignedlongPdu::get_request_id();
//getthePdutype
unsignedshortPdu::get_type();
//returnthevalidityofaPdu
intPdu::valid();
Pduclass可通过重载操作符,赋值或串连Vb对象到Pdu。
//assignmentoperatorforassigningonePdutoanother
Pdu&operator=(constPdu&pdu);
//appendaVbobjecttothePdu’svarbindlist
Pdy&operator+=(Vbvb);
15.5.PduClass处理Traps和Informs的成员函数
当处理notifications,traps和informs的时候,SNMP++提供了成员函数来获取和设置指定的notificationvalue。当使用这些成员函数时,请查阅发送traps和informs的部分。
//setnotifytimestamp
voidPdu::set_notify_timestamp(constTimeTicks×tamp);
//getnotifytimestamp
voidPdu::get_notify_timestamp(TimeTicks×tamp);
//setthenotifyid
voidPdu::set_notify_id(constOidid);
//getthenotifyid
voidPdu::get_notify_id(Oid&id);
//setthenotifyenterprise
voidPdu::set_notify_enterprise(constOid&enterprise);
//getthenotifyenterprise
voidPdu::get_notify_enterprise(Oid&enterprise);
为了在管理应用中使用Pdu对象,必须在Pdu实例中加载“绑定变量表”(vblist)。这可以通过从多种方法中选择你需要的来处理。一般在发送SNMP请求前加载Pdu。
//setnotifytimestamp
voidPdu::set_notify_timestamp(constTimeTicks×tamp);
//getnotifytimestamp
voidPdu::get_notify_timestamp(TimeTicks×tamp);
//setthenotifyid
voidPdu::set_notify_id(constOidid);
//getthenotifyid
voidPdu::get_notify_id(Oid&id);
//setthenotifyenterprise
voidPdu::set_notify_enterprise(constOid&enterprise);
//getthenotifyenterprise
voidPdu::get_notify_enterprise(Oid&enterprise);
为了在管理应用中使用Pdu对象,必须在Pdu实例中加载“绑定变量表”(vblist)。这可以通过从多种方法中选择你需要的来处理。一般在发送SNMP请求前加载Pdu。
//exampleofhowtoloadaPduobject
voidload_pdu_examples()
{
Pdupdu;//createaPduobject
Vbvb;//createaVbobject
vb.set_oid(SYSDECR);//settheoidportionoftheVbtoSystemDescriptor
pdu+=vb;//loadstheVbtothePdu
Pdumy_pdu;//createanotherPduobject
Vbvbs[5];//create5vbs
pdu.set_vblist(vbs,5);//loadall5tothepdu
}
从阻塞或异步请求中得到请求的Pdu后,都需要将Vb卸载下来才能把SMIvalues取出。
//exampleofhowtounloadaPdu
voidunload_pdu_example(Pdu&pdu)
{
insstaus;
Pdupdu;//createaPduobject
Vbvb;//createaVbobject
vb.set_oid(SYSDECR);//settheoidportionoftheVbtoSystemDescriptor
pdu+=vb;//loadstheVbtothePdu
charmessage[100];//forthesystemdescriptorprintableoctet
Snmpsnmp(status);
if(status!=SNMP_CLASS_SUCCESS){
cout<“SNMP++error=“<<snmp.error_msg(status);
return;
}
pdu.get_vb(vb,0);//unloadthevb
vb.get_value(message);//pullthemessageoutofthevb
cout<<message;//printitout
};
SnmpMessageClass允许对SNMP++对象使用抽象编码规则(ASN.1)和基础编码规则(BER)来编码和解码,进而生成可以在线路上传送的SNMP消息。该class可以方便的串行化Pdu对象,以便于后期的各种使用。大多数SNMP++的用户不需要使用这个类,因为Snmpclass已经完成了这项任务,包括管理超时和重发。但是如果程序员想对消息编码,这里也为其提供一种选择,例如很多代理系统就在使用它们自己的传输层。SnmpMessageclass提供的各种成员函数如下表所示:
SnmpMessageClassMemberFunctions |
说明 |
Constructors |
|
SnmpMessage::SnmpMessage(void); |
构造一个空的SnmpMessage对象 |
MemberFunctions |
|
intload(Pdupdu,OctetStrcommunity, snmp_versionversion); |
用Pdu、团体名、版本加载一个SnmpMessage对象。版本可以是SNMPv1或2。返回错误状态。 |
intload(unsignedchar*data,unsignedlongen); |
用原始数据流加载一个SnmpMessage对象。当从线路上收取数据报并通过把它加载到一个SnmpMessage对象来实现解码时,该函数很有用。 |
intunload(Pdu&pdu,OctetStr&community, snmp_version&version); |
卸载一个已经加载过的SnmpMessage对象。由此可以获得Pdu、团体名、版本 |
unsignedchar*data(); |
通过原始的ASN.1/BER串行化数据缓冲区。该缓冲区的范围可以通过成员函数::len()获得 |
unsignedlonglen() |
返回原始数据缓冲区的范围 |
intvalid(); |
判断一个SnmpMessage对象的有效性 |
17.TargetClass
Targetclass是一个C++类,在SNMP++中用它来定义和使用target。一个target在SNMP通讯中,可以想象成一个代理端的管理层的概念,它由多个网络地址组成。Targets包含了重发和超时机制的信息,还有SNMP协议类型(SNMPv1和SNMPv2)等等。目前已有的Targets唯一的子类是Community-basedCTarget。CTargetclass可用在SNMPv1和SNMPv2的通讯上,由此可以重用你已有的代码到SNMPv2通讯中,不需要做修改。通过它,还可以使得一个SNMP++会话与某个特定的代理端的属性无关。
SNMP++支持抽象Target的概念。由该抽象Target可以操作所有实际的Target派生类。所有使用Target的SNMP++成员函数接收的都是抽象Target,而不是特指的派生Target对象。当需要支持新的Target时,这种抽象的接口可以减小代码的改动。
每个target都与一个地址对象(Addressobject)相关联。该地址是一个GenAddress,因此可以处理所有SNMP++地址(IP,IPX或其他)。为指明被管理的代理端地址并与一个Target相关联,只需要简单地通过构造函数的参数或成员函数就可实现。
每个Target都具有重发机制,在该机制中定义了超时和重发。由该重发机制可指定等待一个SNMP应答的周期,以及当没有收到一个SNMP应答时进行多少次重发。超时的最小单位被定义成百分之一秒,即当取值为100代表每个应答等待1秒。重发时记录了重发的次数,注意,第一次请求不属于重发,只是发送。所以重发值取3,表示当等待一个应答时最多可以重发3次。等待的总时间可以用下列式子计算:TotalWaitTime=time-out*(retry+1)
如果一个SNMP++应答没有在上式所计算出来的等待总时间内到来,将会返回一个SNMP++超时的错误号。该操作在阻塞和异步两种调用中都可使用。
TargetClassMemberFunctions |
说明 |
Constructors |
|
CTarget::CTarget(void); |
构造一个无效的CTarget。重发机制的默认值:communitynames=“public”,retry=1,time_out=1。 |
CTarget::CTarget(constAddress&address, constchar*read_community_name, constchar*write_community_name, |
用communitynames和Addressobject构造一个CTarget。重发机制的默认值:retry=1,time-out=100ms。 |
CTarget(constAddress&address constOctetStr&read_community_name, constOctetStr&write_community_name); |
用OctetStrCommunities和Address构造一个CTarget |
CTarget::CTarget(Address&address); |
用Addressobject构造一个CTarget。重发机制的默认值:communitynames=“public”,retry=1,time_out=1。 |
CTarget::CTarget(constCTarget&target); |
拷贝构造函数 |
Destructor |
|
CTarget::~CTarget(); |
删除CTarget对象,释放所有资源。 |
MemberFunctions |
|
char*get_readcommunity(); |
返回读权限的community名称 |
voidget_readcommunity(OctetStr&read_community_oct); |
获取OctetStr格式的读权限community |
voidset_readcommunity(constchar*get_community); |
设置读权限community |
voidset_readcommunity(constOctetStr&read_community); |
用一个OctetStr设置读权限community |
char*get_writecommunity(); |
获取写权限community |
voidget_writecommunity(OctetStr&write_community_oct); |
获取OctetStr格式的写权限community |
voidset_writecommunity(constchar*new_set_community); |
设置写权限community |
voidset_writecommunity(constOctetStr&write_community); |
用一个OctetStr设置写权限community |
intget_address(GenAddress&address); |
获取Addressobject. |
voidset_address(Address&address); |
设置Address部分 |
CTarget&operator=(constCTarget&target); |
把一个CTarget赋给另一个。 |
snmp_versionget_version(); |
返回SNMP版本(version1或version2) |
voidset_version(constsnmp_versionv); |
设置版本(version1或version2) |
intoperator==(constCTarget&lhs,constCTarget&rhs); |
比较两个CTargets |
AbstractClassMemberFunctions |
|
intvalid(); |
返回一个Target的有效性 |
voidset_retry(constintr); |
设置重发值 |
intget_retry(); |
获取重发值 |
voidset_timeout(constunsignedlongt); |
设置超时值 |
unsignedlongget_timeout(); |
获取超时值 |
17.5.CTargetClass(以Community为基础的Target)
CTargetclass允许显示地定义以Community为基础的Target。一个CTarget用以SNMPCommunity为基础的Target定义了一个SNMP代理端。这包含了“读权限、写权限”的communitynamesandanaddress。地址是用SNMP++Addressclass来表示的,所以该地址可以是IP或者IPXaddress(Addressclass是个抽象基类,所以可以实现多态操作)。CTargetclass使用前提应该是:应用开发者明确地知道代理端所支持的以SNMPcommunity为基础的访问方式,即SNMPv1或SNMPv2。
//----------[instantiatingCTargetObjects]-----------------------------
//validcompleteinstantiation
CTargetct((IpAddress)”10.10.10.10”,//Address
“public”,//readcommunityname
“public”);//writecommunityname
//validcompleteusing“public”defaults
CTargetct((IpAddress)“1.2.3.4”);
//invalidCTarget
CTargetct;
17.5.2.修改CTargets
//----[modifyingCTargets]------------------------------------
ct.set_readcommunity(“private);//modifyingthereadcommunity
ct.set_writecommunity(“private”);//modifyingthewritecommunity
ct.set_address((IpAddress)“15.29.33.210”);
//-----[AccessingCTargetmembervariables]-------------------------
//getthewritecommunityname
cout<<“Writecommunity”<<ct.get_writecommunity();
//getthereadcommunityname
cout<<“Readcommunity”<<ct.get_readcommunity();
//gettheaddress
GenAddressaddress;
ct.get_address(address);
//checkthevalidityofatarget
if(ct.valid())
cout<<“Targetisvalid”;
//------------[CTargetclassexamples]-----------------------------------------------------------------
//createavalidCTargetusingaGenAddress
CTargetct((GenAddress)“10.20.30.40”);
//createavalidCTargetusinganIpxAddress
IpxAddressipxaddress(“01010101-010101010101”);
CTargetmy_target(ipxaddress);//usedefault“public”forcommunities
//createaninvalidCTargetobject
CTargetct;//noconstructionparamsthereforinvalid
if(!ct.valid())
cout<<“InvalidCTargetinstance!”;
//getthereadcommunity
cout<<“ReadCommunity=”<<ct.get_readcommunity();
//getthewritecommunity
cout<<“WriteCommunity=”<<ct.get_writecommunity();
//modifythegetcommunity
ct.set_readcommunity(“pilsner”);
//modifythewritecommunity
ct.set_writecommunity(“paleale”);
18.SnmpClass
SNMP++之SnmpClass的对象模型(ObjectModelingTechnique)视图
Snmpclass是SNMP++中最为重要的类。Snmpclass封装了SNMP的会话。通过处理与指定代理端的会话,SNMP++实现了对网络管理应用的逻辑绑定。会话所控制的是PDU的构建、分发、接受。其他大多数API需要程序员直接操作会话,也即需要提供可靠的传输机制来控制超时、重发、查重。Snmpclass管理了大部分的会话,得到解放的程序员只需要关注于代理端的管理,方便了代码的开发和测试。如果不这样(没有SNMP++),你就只有去设计、实现、测试你自己的SNMP引擎。那么Snmpclass是如何管理通信的呢:1、在UDP或IPX连接基础上管理传输层;2、负责打包和解包PDU中的绑定变量;3、分发和接收PDU;4、管理所有SNMP所需的资源。
Snmpclass使用简单。它为网络管理应用提供了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(),即“陷阱”和“通知”的接收。
Snmpclass使用安全。构造函数和析构函数完成了对所有资源的加载和卸载,从而减小了内存的崩溃和泄漏的可能性。所有SNMP的内部机制都隐藏起来了,也就避免了不小心而修改到这些内部机制。
Snmpclass可移植。对操作系统和网络系统而言,Snmpclass的接口是可移植的。绝大多数SNMP++的类都可以在任何ANSI/ISOC++编译器上编译和使用。只需要修改少量代码,就可以实现对SNMP++的平台切换。
18.1.SnmpClass成员函数列表
SnmpClassMemberFunctions |
说明 |
Constructor |
|
Snmp::Snmp(int&status); |
构造一个Snmp对象,status定义的是成功状态 |
Destructor |
|
Snmp::~Snmp(); |
销毁,释放所有资源,关闭会话 |
MemberFunctions |
|
char*error_msg(constintstatus); |
返回所给错误状态的文本字符串 |
intget(Pdu&pdu,SnmpTarget&target); |
|
intset(Pdu&pdu,SnmpTarget&target); |
调用阻塞方式的SNMPset。对target设置Pdu |
intget_next(Pdu&pdu,SnmpTarget&target); |
调用阻塞方式的SNMPgetnext。针对target上的Pdu |
intget_bulk(Pdu&pdu,SnmpTarget&target, constintnon_repeaters, constintmax_reps); |
调用阻塞方式的SNMPgetbulk(但是V2targets只使用get-next) |
intinform(Pdu&pdu,SnmpTarget&target); |
调用阻塞方式的inform |
intget(Pdu&pdu, snmp_callbackcallback, void*callback_data=0); |
|
intset(Pdu&pdu, void*callback_data=0); |
|
intget_next(Pdu&pdu, void*callback_data=0); |
|
intget_bulk(Pdu&pdu, constintmax_reps snmp_callbackcallback, void*callback_data=0); |
|
intinform(Pdu&pdu, void*callback_data=0); |
调用异步inform。需要用到notify的回调。 |
inttrap(Pdu&pdu,SnmpTarget&target); |
向指定的target发送一个trap |
intnotify_register(TargetCollection&targets, OidCollection&trapids, void*callback_data=0); |
对接收trap和inform的操作注册 |
intnotify_register(TargetCollection&targets, AddressCollection&listen_addresses, void*callback_data=0); |
对接收trap和inform的操作注册,并用AddressCollection指出监听的接口。 |
intnotify_unregister(); |
撤消对接收trap和inform的操作注册 |
intcancel(constunsignedlongrid); |
取消针对所给请求id的异步请求的等待 |
所有的Snmpclass成员函数都是双效的。这就是说对于SNMPversion1或version2c,他们可以使用统一的参数表。这解放了程序员,因为程序员不用为了与SNMPversion2的代理端通讯而去修改代码。
18.3.SnmpClass的公共成员函数
通过SnmpClass提供的许多成员函数可以创建、管理、终结一个会话。多个Snmp对象可以在同一时间建立。
18.3.1.SnmpClass的构造和析构函数
SnmpClass的构造和析构函数允许开启和关闭会话。通过构建一个Snmp对象来开启一个Snmp会话。由此可对UDP或IPX套接口实现构建和管理,直到对象被销毁。Snmp对象可选择被动态或静态的实例化。
18.3.2.SnmpClass构造函数
该构造函数以参数方式返回状态(status)。因为C++的构造函数没有返回值,调用者必须提供一个状态值(status)以供实例化对象后针对状态的检查。调用者需要检查返回值是否是“SNMP_CLASS_SUCCESS”。如果构造函数的状态不表示成功,该会话也就不可用。
//constructor,blockedSNMPobject
Snmp::Snmp(int&status);//constructionstatus
18.3.3.SnmpClass析构函数
SnmpClass的析构函数关闭相应的会话,并释放所有资源和内存
//destructor
Snmp::~Snmp();
18.3.4.SnmpClass发送请求的成员函数
为了访问或修改代理端的MIB,请求必须通过Snmp::get(),Snmp::set(),Snmp::get_next(),Snmp::get_bulk(),Smnp::inform()以及Snmp::trap()来发送。所有这些成员函数接受同样的参数表。
18.3.5.SnmpClass的阻塞方式成员函数:Get
阻塞方式的成员函数get允许从指定target的代理端获取对象。调用者必须指定目标target以及要请求的Pdu。
//--------[get]-------------------------------------------
intSnmp::get(Pdu&pdu,//Pdutoget
SnmpTarget&target);//specifiedtarget
18.3.6.SnmpClass的阻塞方式成员函数:GetNext
阻塞方式的成员函数getnext可以用来遍历代理端的MIB。
//---------[getnext]--------------------------------------
intSnmp::get_next(Pdu&pdu,//Pdutogetnext
SnmpTarget&target);//specifiedtarget
18.3.7.SnmpClass的阻塞方式成员函数:Set
阻塞方式的成员函数set允许设置代理端的对象
//---------[set]--------------------------------------------
intSnmp::set(Pdu&pdu,//Pdutoset
SnmpTarget&target);//specifiedtarget
18.3.8.SnmpClass的阻塞方式成员函数:GetBulk
SNMP++为SNMPversion1和version2的Target提供了一个获取批量数据的接口。在SNMPversion1中的相应操作对应到成员函数getnext。
//--------[getbulk]-------------------------------------------
intSnmp::get_bulk(Pdu&pdu,//pdutoget_bulk
Target&target,//destinationtarget
constintnon_repeaters,//nonrepeaters
constintmax_reps);//maximumreps
18.3.9.SnmpClass的阻塞方式成员函数:Inform
SNMP++提供了一个Inform接口,由此可直接在V2的代理端和网管端内部之间发送消息。
//-----------[inform]----------------------------------------------------------
intSnmp::inform(Pdu&pdu,//pdutosend
SnmpTarget&target);//destinationtarget
为一个Inform指定其Id
InformID的指定方法与trapID一样。可通过用成员函数Pdu::set_notify_id()来为一个inform的PDU指定其ID。Inform标识符ID代表了其使用的Oid。为了建立InformID,可以用需要的InformID值来直接建立一个Oid对象,然后用成员函数Pdu::set_notify_id()把一个Pdu加载在其上。反过来,一个inform的ID可以用成员函数Pdu::get_notify_id()来获取。
在Inform上指定TimeStamp时间信息
要给一个informPDU指定时间信息,可用成员函数Pdu::set_notify_timestamp()。如果一个Pdu没有用该成员函数就发出去了,那么会使用一个来自SNMP++引擎默认的timestamp。
18.4.SnmpClass的异步方式成员函数
一个Snmp实例可以支持阻塞与异步两种方式的请求。异步请求将会立即返回所控制的线程,并不需要等待呼叫者的应答。为了达到该目的,使用了所谓的回调程序机制。当发出异步请求时,调用者必须指定回调函数,还可选择性的指定一个回调函数的参数。
18.4.1.SNMP++异步回调函数的类型定义
typedefvoid(*snmp_callback)(int,//reason
Snmp*,//sessionhandle
Pdu&,//Pdupassedin
SnmpTarget&,//sourcetarget
void*);//callbackdata
18.4.1.1.回调的参数说明
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()来获得notificationid,timestamp和enterprise。
Snmp++Session,Snmp*
该参数保存发送请求的会话的值。由此可以在time-out或get-next情况下实现会话的重用。
ResponsePDU,Pdu&
该参数为esponse,notifie和trap保存了“应答Pdu”。当“原因”(reason参数)为“失败”时,Pdu参数保存了“请求Pdu”的原值。一旦Pdu对象越界,其值就不可得了。
Target,SnmpTarget&
该参数为response,notifie和trap保存了Pdu的来源。如果“原因”(reason参数)为“失败”,当有请求发出时,target的原值就会被用到。
Callbackdata,void*
当有请求发出时,回调的参数可以作为一个可选的参数提供。如果指定了该参数,将会返回相关信息。如果没有指定,该值取空(null)。
SNMP++允许在完成之前取消相应的异步请求。这很有用,尤其当你需要在代码中提前退出或指定的回调已经失效的时候。当Snmp对象发出的请求被销毁时,异步请求会自动取消,这时指定的回调会收到一个“SNMP_CLASS_SESSION_DESTROYED”的原因。另一方面,可以用成员函数Snmp::cancel()来取消单个的异步请求。该成员函数通过参数request_id无影响的取消对应的异步请求。
//-------------[cancelarequest]-----------------------------------
intSnmp::cancel(constunsignedlongrid);
18.4.3.SnmpClass的异步成员函数:Get
异步get允许从指定的代理端获取SNMP对象。当“请求PDU”发出后,异步get调用就会返回,它不会等待“应答PDU”。当收到“应答PDU”时,会调用程序员定义的回调。在回调中,可以用任何喜欢的方式实现有效的应答。
//------------------------[getasync]----------------------------------
intSnmp::get(Pdu&pdu,//Pdutogetasync
SnmpTarget&target,//destinationtarget
snmp_callbackcallback,//asynccallback
void*callback_data=0);//callbackdata
18.4.4.SnmpClass的异步成员函数:Set
异步成员函数set的工作方式与get雷同。
//------------------------[setasync]----------------------------------
intSnmp::set(Pdu&pdu,//Pdutosetasync
SnmpTarget&target,//asynccallback
void*callback_data=0);//callbackdata
18.4.5.SnmpClass的异步成员函数:GetNext
异步成员函数get-next的工作方式与异步get和set雷同。
//------------------------[getnextasync]-----------------------------
intSnmp::get_next(Pdu&pdu,//Pdutoget_next
SnmpTarget&target,//destination
snmp_callbackcallback,//asynccallback
void*callback_data=0);//callbackdata
18.4.6.SnmpClass的异步成员函数:GetBulk
异步成员函数get-bulk的工作方式与异步get和set雷同。
//------------------------[getbulkasync]-----------------------------
intSnmp::get_bulk(Pdu&pdu,//Pdutoget_bulkasync
Target&target,//nonrepeaters
constintmax_reps,//maxrepetitions
snmp_callbackcallback,//asynccallback
void*callback_data=0);//callbackdata
18.4.7.SnmpClass的异步成员函数:Inform
//--------------------[informasync]----------------------------------------
intSnmp::inform(Pdu&pdu,//pdutosend
SnmpTarget&target,//callbackfunction
void*callback_data=0);//callbackdata
发送trap的函数是一个有用的管理程序(manager)API。可用函数与其他管理端进行通讯。
//-----------------------[sendatrap]----------------------------------
intSnmp::trap(Pdu&pdu,//Pdutosend
SnmpTarget&target);//destinationtarget
18.5.1.1.发送Trap的成员函数的参数说明
Pdu&pdu
要发送的Pdu,它是trap所包含的有效负载。
SnmpTarget&target
发送Trap的目的地
指定一个Trap的Id
TrapId的指定方式与InformId一样。可用成员函数Pdu::set_notify_id()来指定trapPDU的ID。Trap标识符ID在SMISNMPv2中是以Oid表示的。SNMP++预定义了以下6种通用的trapOid。只需用想要的trapid值来赋给一个Oid对象就可以生成一个trapid。相反的,可用成员函数Pdu::get_notify_id()来获取trapid。
SNMP++为通用TrapID定义的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()来指定trapPDU的时间信息。如果一个Pdu没调用这个成员函数就发送了,那么会使用一个来自SNMP++引擎的时间信息。
18.5.1.2.指定TrapEnterprise
不用被企业指定的trap困扰,任何trap的企业都代表了产生trap的代理端的MIB。对trap的发送者来说它是系统标识符(SystemObjectIdentifier),但是从理论上讲它可以表示任何Oid的值。为了设置该参数,SNMP++允许使用成员函数Pdu::set_notify_enterprise()来设置enterprise,而且这个参数是可选的。如果使用了所提供的enterprise,该enterprise会加载在对应的Pdu对象上。
18.5.1.3.给SNMPv1Trap指定特殊的Trap值
为了给SNMPv1Trap指定特殊的Trap值,trapid的Oid应该构造如下:trapid的最末子id(subid)代表指定的要使用的值;倒数第二个子id应该是零。即,为了指定特殊的Trap值,需要添加两个额外的子id,一个是零、一个是值(“0.X”)。这个约定与规定SNMPv1和SNMPv2trap映射的RFC1452的描述一致。
接收SNMP++trap和inform的时候,允许应用程序使用指定的过滤器来接收trap和inform。不像其他的SNMP操作,trap和inform是在任何可能出现的时候主动发出的。因此informs和traps属于异步的动作。通过SNMP++提供的成员函数,调用者可以指定informs和traps的过滤器。可用informs和traps的类型、来源和目标来过滤informs和traps。
//-----------------------[registertoreceivetrapsandinforms]-------------------------------------------
//defaultformlistensonalllocalinterfacesusingwellknownport/socket#’s
intSnmp::notify_register(OidCollection&ids,//typestolistenfor
TargetCollection&targets,//targetstolistenfor
snmp_callbackcallback,//callbacktouse
void*callback_data=0);//optionalcallbackdata
//------------------------[registertoreceivetrapsandinforms]----------------------------------------
//alternateform,AddressCollectionallowslocallisteninterfacespecification
intSnmp::notify_register(OidCollection&ids,//targetstolistenfor
AddressCollection&local_interfaces,//interfacestolistenon
snmp_callbackcallback,//callbacktouse
void*callback_data=0);//optionalcallbackdata
//-----------------------[un-registertogettrapsandinforms]------------------------------------------
intSnmp::notify_unregister();
18.5.2.1.注册Trap和Inform
每个Snmpclass实例可以为它们自己的traps/informs注册。也就是说,一个Snmp对象可以有它自己的一套过滤器和回调,当收到的trap或inform满足过滤条件时就会调用。当每个新的呼叫清理了先前的过滤器设置时,成员函数Snmp::notify_register()可能会多次被调用。当调用成员函数Snmp:notify_unregister()或Snmp实例撤消时,相应的接收Trap/inform的会话将会终止。
18.5.2.2.Snmp::notify_register()的基本形式
notification的注册基本形式中包括:notification类型、notification来源、过滤参数、OidCollection和TargetCollection。使用该形式的notify_register()会在所有本地端口上触发notification的监听。所以如果本地机器有多重初始地址,即它会有多重网络接口,所有的接口将会被开启,并使用已知的port/socket来接收notify。例如:如果我的机器是双网卡的,两个卡都支持IP(InternetProtocol)协议,其中一个还支持IPX(InternetExchangeProtocol)协议;如果调用基本形式的notify_register(),则会在两个IP接口上使用已知的SNMPtrap端口,在IPX接口上使用已知的trapIPX套接字(socketnumber)。
18.5.2.3.Snmp::notify_register()的备用形式
作为备用,重载形式的notify_register()可接受一个附加参数,进而允许指定本地接口来监听inform或AddressCollection。AddressCollection参数包含了一组需要监听的Address对象列表,包括:IpAddresses,IpxAddresses,UdpAddresses和IpxSockAddresses。下表描述了AddressCollection以及notify_register()的运作方式:
AddressCollectionElementBehaviorDefinition
AddressClass |
Value |
说明 |
IpAddress |
Anyvalueexcept0.0.0.0 |
用已知的IP端口监听指定的IP接口 |
IpAddress |
0.0.0.0 |
用已知的IP端口监听所有IP接口 |
UdpAddress |
Anyvalueexcept0.0.0.0 |
用已知的UDP端口监听指定的UDP接口 |
UdpAddress |
0.0.0.0 |
用已知的UDP端口监听所有UDP接口 |
IpxAddress |
Anyvalueexcept00000000:000000000000 |
用已知的IPX端口监听指定的IPX接口 |
IpxAddress |
00000000:000000000000 |
用已知的IPX端口监听所有IPX接口 |
IpxSockAddress |
Anyvalueexcept00000000:000000000000 |
用已知的IPX套接字监听指定的IPX接口 |
IpxSockAddress |
00000000:000000000000 |
用已知的IPX套接字监听所有IPX接口 |
18.5.2.4.notify_regsiter()的过滤功能
当需要过滤时,过滤器的行为如下:如果收到的inform或trap与OidCollection中的id单元(item)一致,并且收到的inform或trap与TargetCollection中的单元一致,则相应的inform/trap会被送到调用者指定的回调中。注意,如果OidCollection为空,则所有的inform都将通过id检查,同样的,如果TargetCollection为空,则所有的inform都将通过Target检查。
18.5.3.使用OidCollection,TargetCollection和AddressCollections过滤
SNMP++提供了3种有序集合的collectionclasse,共同来收集Oids,Targets和Addresses。所有collectionclasse操作形式都一样,因为它们是从同样的C++模板类SnmpCollection派生来的。统一的集合操作如下:
TargetandOidCollectionClassMemberFunctions |
说明 |
Constructors |
|
SnmpCollection::SnmpCollection(void); |
构造一个空的集合 |
SnmpCollection::SnmpCollection(constT&t); |
用单一元素构造一个集合 |
Destructors |
|
SnmpCollection::SnmpCollection(); |
销毁集合,释放所有资源 |
MemberFunctions |
|
intsize(); |
返回集合的大小 |
SnmpCollection&operator+=(T&t); |
增加一个元素到集合 |
SnmpCollection&operator=(SnmpCollection&collection); |
将一个集合赋给另一个 |
T&operator[](intp); |
访问集合中的一个元素 |
intset_element(constT&i,constintp); |
在集合种设置一个已有的元素 |
intget_element(T&i,constintp); |
从集合获取一个元素 |
18.5.3.1.生成并使用集合作为过滤器
生成并使用SnmpCollections作为接收一个trap/inform的过滤器是简单而直接的。Notify的注册函数有3个参数:TargetCollection,OidCollection和AddressCollection。要构造这些过滤器,首先得实例化一个集合,然后用重载的操作符“+=”把元素加入其中。
//exampleofmakingtrapreceptionfilters
//targetcollection
TargetCollectionmy_targets;
my_targets+=cisco_router;
my_targets+=fore_switch;
//Oidcollection
OidCollectionmy_trapids;
my_trapids+=coldStart;
my_trapids+=warmStart;
//Addresscollection
AddressCollectionmy_addresses;
my_addresses+=(IpAddress)“10.4.8.5”;
my_addresses+=(GenAddress)“01020304:010203040506”;
18.6.SNMP++Class返回的错误号
使用SNMP++时,可返回多种错误编号。这些错误号可穿越平台,进而帮助应用的开发者发现并检查错误条件。
如果在使用Snmp成员函数过程中出现了一个错误,成员函数Snmp::error_msg()可以用来检索出一个友好的错误字符串。
//------------------------[errormessage]-----------------------------
char*Snmp::error_msg(constintstatus);//returnsstringforprovidedstatus
SNMP++的设计决定了它支持多种运行模式。这些运行模式允许用户创建图形用户接口(GUI)以及控制台模式的应用。GUI运行模式与现有的GUI事件驱动系统协同工作;而控制台运行模式允许使用自定义的事件驱动系统,甚至不需要事件驱动系统。
19.1.MicrosoftWindows事件驱动系统的运作
为了在MS-Windows上使用,SNMP++与MS-Windows消息系统协同工作。调用阻塞模式可以允许处理其他消息。
19.2.OpenSystemsFoundation(OSF)X11Motif的运作
X11接口与MS-Windows接口一样。在MS-Windows和X11各种版本上的SNMP++都支持阻塞和异步方式的使用。为了用SNMP++对X11应用注册X11的上下文(context)需要一个额外的函数(该操作是为了在X11的事件系统上使用SNMP++)。这就要用到XtAppMainLoop()或类似的函数来显式地认可并分发所有异步的SNMP++事件。
·需要传入的上下文参数会由XtAppInitialize()的调用返回
//----------------[initializeSNMP++X11Context]--------------------------
intSNMPX11Initialize(XtAppContextcontext);
SNMP++的第三种运作模式是用文本形式构造的控制台应用。这些类型的应用上的操作也可以调用阻塞或异步的模式。SNMP++提供了一组函数调用来读取当前用到的文件描述符(sockethandles)。调用者在它们各自的“select”调用中用到这些文件描述符。如果SNMP++文件描述符有一个挂起的事件,调用者将激活例行程序来处理所有挂起的事件。
SNMPGetFdSets
用以决定需要潜在地激活的文件描述符。该函数会填充读、写、异常模块,以便传递到“select”。
//-------[getfiledescriptorsetfromSNMP++]------------------------------------
voidSNMPGetFdSets(int&maxfds,//max#offdsrepresented
fd_set&read_fds,//maskrepresentingreadactions
fd_set&write_fds,//maskrepresentingwriteactions
fd_set&exceptfds);//maskrepresentingexceptionactions
SNMPGetNextTimeout
用以决定下次出现超时事件的时间。该值可在阻塞操作中被用作最大间隔值。比如select在控制权返回之前必须等待该间隔时间。超时的计算的基础是:所有用户注册超时(user-registeredtime-outs)以及SNMP重发的时间间隔中最近的一次。
//---------[Getthenexttime-outvalue]----------------------------------------------------
unsignedlongintSNMPGetNextTimeout();//returnsvaluein1/100ofseconds
SNMPProcessPendingEvents
用以处理目前所有的突出的(outstanding)事件。该函数会调用所有与已完成的超时、文件描述符或突出的(outstanding)SNMP消息相关的回调。该函数是非阻塞的,在同一时候它只处理突出的(outstanding)事件。
//------[processpendingevents]----------------------------------------------------------
intSNMPProcessPendingEvents();
20.状态&错误编号
当使用Snmpclass操作的时候SNMP++提供了两种级别的错误信息。所有的Snmpclass成员函数都返回一个状态值。“SNMP_CLASS_ERR_STATUS_SET”这个特别的错误值表明了Pdu发生了一个内部错误,必须用成员函数Pdu::get_error_status()来检索该错误信息。所有的SNMP++错误值都可传进成员函数Snmp::err_msg()以打印出该错误的文本描述。
SNMP++GeneralErrors |
Value |
说明 |
SNMP_CLASS_SUCCESS |
0 |
成功状态 |
SNMP_CLASS_ERROR |
-1 |
普通错误 |
SNMP_CLASS_RESOURCE_UNAVAIL |
-2 |
内存分配失败(New或malloc) |
SNMP_CLASS_INTERNAL_ERROR |
-3 |
未知的内部错误 |
SNMP_CLASS_UNSUPPORTED |
-4 |
|
CallbackReasons |
||
SNMP_CLASS_TIMEOUT |
-5 |
明显的请求超时 |
SNMP_CLASS_ASYNC_RESPONSE |
-6 |
收到应答 |
SNMP_CLASS_NOTIFICATION |
-7 |
收到notification(trap/inform) |
SNMP_CLASS_SESSION_DESTROYED |
-8 |
销毁Snmp对象 |
SnmpClassErrors |
||
SNMP_CLASS_INVALID |
-10 |
|
SNMP_CLASS_INVALID_PDU |
-11 |
向映像函数传递了无效的PDU |
SNMP_CLASS_INVALID_TARGET |
-12 |
向映像函数传递了无效的target |
SNMP_CLASS_INVALID_CALLBACK |
-13 |
|
SNMP_CLASS_INVALID_REQID |
-14 |
要取消的请求ID无效 |
SNMP_CLASS_INVALID_NOTIFYID |
-15 |
trap/informOid丢失 |
SNMP_CLASS_INVALID_OPERATION |
-16 |
指定的target不允许进行Snmp操作 |
SNMP_CLASS_INVALID_OID |
-17 |
向映像函数传递了无效的Oid |
SNMP_CLASS_INVALID_ADDRESS |
-18 |
向映像函数传递了无效的address |
SNMP_CLASS_ERR_STATUS_SET |
-19 |
代理端返回带有错误信息的应答PDU |
SNMP_CLASS_TL_UNSUPPORTED |
-20 |
不支持的传输 |
SNMP_CLASS_TL_IN_USE |
-21 |
传输被占用 |
SNMP_CLASS_TL_Failed |
-22 |
传输失败 |
21.错误状态值
当SNMP++的成员函数返回值是“SNMP_CLASS_ERR_STATUS_SET”时,可以由成员函数Pdu::get_error_status()获取一个额外的错误状态。该值表示的是RFC1905中实际的SMIPDU错误状态值。这些值可以传进成员函数Snmp::err_msg()以友好的方式描述。
PduErrorStatusMacro |
Value |
说明 |
SNMP_ERROR_TOO_BIG |
1 |
Pdu太大,查看错误索引 |
SNMP_ERROR_NO_SUCH_NAME |
2 |
|
SNMP_ERROR_BAD_VALUE |
3 |
|
SNMP_ERROR_READ_ONLY |
4 |
帮定变量是只读的,查看返回的错误索引 |
SNMP_ERROR_GENERAL_VB_ERR |
5 |
|
SNMP_ERROR_NO_ACCESS |
6 |
操作失败,拒绝访问 |
SNMP_ERROR_WRONG_TYPE |
7 |
操作失败,类型错误 |
SNMP_ERROR_WRONG_LENGTH |
8 |
操作失败,长度错误 |
SNMP_ERROR_WRONG_ENCODING |
9 |
操作失败,译码错误 |
SNMP_ERROR_WRONG_VALUE |
10 |
操作失败,值错误 |
SNMP_ERROR_NO_CREATION |
11 |
操作失败,拒绝创建 |
SNMP_ERROR_INCONSIST_VAL |
12 |
操作失败,值不相容 |
SNMP_ERROR_RESOURCE_UNAVAIL |
13 |
操作失败,无法使用资源 |
SNMP_ERROR_COMITFAIL |
14 |
操作失败,提交失败 |
SNMP_ERROR_UNDO_FAIL |
15 |
操作失败,撤销失败 |
SNMP_ERROR_AUTH_ERR |
16 |
操作失败,权限错误 |
SNMP_ERROR_NOT_WRITEABLE |
17 |
操作失败,拒绝更改 |
SNMP_ERROR_INCONSIS_NAME |
18 |
操作失败,名字不相容 |
关于这个部分的附加例子,请查阅下表所列的文档,以获得可用作命令的完整实用程序。
ProgramNameand说明 |
FileName |
SnmpGet,performsSNMP++gettov1andv2agents. |
snmpget.cpp |
SnmpNext,peformsSNMP++getNexttov1andv2agents. |
snmpnext.cpp |
SnmpBulk,performsSNMP++getBulktov1andv2agents. |
snmpbulk.cpp |
SnmpSet,performsSNMP++settov1andv2agents. |
snmpset.cpp |
SnmpTrap,sendsv1orv2traptoamanager. |
snmptrap.cpp |
SnmpWalk,walksanagent'sMIBusingv1orv2viaGetBulk. |
snmpwalk.cpp |
22.1.GettingaSingleMIBVariableExample
#include“snmp_pp.h”
#defineSYSDESCR“1.3.6.1.2.1.1.1.0”//ObjectIDforSystemDescriptor
voidget_system_descriptor()
{
intstatus;//returnstatus
CTargetctarget((IpAddress)“10.4.8.5”);//SNMP++v1target
Vbvb(SYSDESCR);//SNMP++VariableBinding
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
//-------[InvokeaSNMP++Get]-------------------------------------------------------
pdu+=vb;//addthevariablebinding
if((status=snmp.get(pdu,0);//extractthevariablebinding
cout<<“SystemDescriptor=”<<vb.get_printable_value();}//printout
};
22.2.GettingMultipleMIBVariablesExample
#include“snmp_pp.h”
#defineSYSDESCR“1.3.6.1.2.1.1.1.0”//ObjectIDforsystemdescriptor
#defineSYSOBJECTID"1.3.6.1.2.1.1.2.0"//ObjectIDforsystemobjectID
#defineSYSUPTIME"1.3.6.1.2.1.1.3.0"//ObjectIDforsystemuptime
#defineSYSCONTACT"1.3.6.1.2.1.1.4.0"//ObjectIDforsystemcontact
#defineSYSNAME"1.3.6.1.2.1.1.5.0"//ObjectIDforsystemname
#defineSYSLOCATION"1.3.6.1.2.1.1.6.0"//ObjectIDforsystemlocation
#defineSYSSERVICES"1.3.6.1.2.1.1.7.0"//ObjectIDforsystemservices
voidget_system_group()
{
intstatus;//returnstatus
CTargetctarget((IpAddress)“10.4.8.5”);//SNMP++v1target
Vbvb[7];//avbforeachobjecttoget
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
//-------[buildupthevbstoget]-----------------------------------------------------------------
vb[0].set_oid(SYSDESCR);
vb[1].set_oid(SYSOBJECTID);
vb[2].set_oid(SYSUPTIME);
vb[3].set_oid(SYSCONTACT);
vb[4].set_oid(SYSNAME);
vb[5].set_oid(SYSLOCATION);
vb[6].set_oid(SYSSERVICES);
//----[appendallthevbstothepdu]-----------------------------------------------------
for(intz=0;z<7;z++)
pdu+=vb[z];
//-------[InvokeaSNMP++Get]-------------------------------------------------------
if((status=snmp.get(pdu,ctarget))!=SNMP_CLASS_SUCCESS)
cout<<snmp.error_msg(status);
else{
pdu.get_vbs(vb,7);//extractthevariablebindings
for(intw=0;w<7;w++)
cout<<vb[w].get_printable_value()<<“\n”;}//printoutthevalue
};
22.3.SettingaSingleMIBVariableExample
#include“snmp_pp.h” #defineSYSLOCATION“1.3.6.1.2.1.1.6.0”//ObjectIDforSystemlocation voidset_system_location() { intstatus;//returnstatus CTargetctarget((IpAddress)“10.4.8.5”);//SNMP++v1target Vbvb(SYSLOCATION);//SNMP++VariableBinding Pdupdu;//SNMP++PDU //-------[ConstructaSNMP++SNMPObject]--------------------------------------- Snmpsnmp(status);//CreateaSNMP++session if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus cout<<snmp.error_msg(status);//iffail,printerrorstring return; } //-------[InvokeaSNMP++Set]------------------------------------------------------- vb.set_value(“UpstairsMezzanine”);//addlocationstringtovb pdu+=vb;//addthevariablebinding status=snmp.set(pdu,ctarget); cout<<snmp.error_msg(status); } |
22.4.SettingMultipleMIBVariablesExample
#include“snmp_pp.h”
#defineSYSCONTACT"1.3.6.1.2.1.1.4.0"//ObjectIDforsystemcontact
#defineSYSNAME"1.3.6.1.2.1.1.5.0"//ObjectIDforsystemname
#defineSYSLOCATION"1.3.6.1.2.1.1.6.0"//ObjectIDforsystemlocation
voidmulti_set()
{
intstatus;//returnstatus
CTargetctarget((IpAddress)“10.4.8.5”);//SNMP++v1target
Vbvb[3];//avbforeachobjecttoget
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
//-------[buildupthevbstoget]-----------------------------------------------------------------
vb[0].set_oid(SYSCONTACT);
vb[0].set_value(“AlanTuring”);
vb[1].set_oid(SYSNAME);
vb[1].set_value(“TheTuringMachine”);
vb[2].set_oid(SYSLOCATION);
vb[2].set_value(“Cambridge,UK”);
//----[appendallthevbstothepdu]-----------------------------------------------------
for(intz=0;z<3;z++)
pdu+=vb[z];
//-------[InvokeaSNMP++Set]-------------------------------------------------------
status=snmp.set(pdu,ctarget);
cout<<snmp.error_msg(status);
}
22.5.WalkingaMIBusingGet-NextExample
#include“snmp_pp.h”//includesnmp++headerfile
voidmib_walk()
{
intstatus;//returnstatus
CTargettarget((IpAddress)“10.4.8.5”);//SNMP++v1target
Vbvb;//aSNMP++vb
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
//-------[setupthefirstvb]---------------------------------------------------------------
vb.set_oid(“1”);//getnextstartingseed
pdu+=vb;//addvbtothepdu
status=SNMP_CLASS_SUCCESS;
while(status==SNMP_CLASS_SUCCESS)
{
if((status=snmp.get_next(pdu,ctarget))==SNMP_CLASS_SUCCESS){
pdu.get_vb(vb,0);//extractthevb
cout<<“MibObject=“<<vb.get_printable_oid()<<“\n”;
cout<<“MibValue=“<<vb.get_printable_value()<<“\n”;
pdu.set_vb(vb,0);//uselastvbasthenextone
}
else
cout<<“SNMP++Error=“<<snmp.error_msg(status);
}
};
#include“snmp_pp.h”
voidsend_trap()
{
intstatus;//returnstatus
CTargettarget((IpAddress)“10.4.8.5”);//SNMP++v1target
Pdupdu;//SNMP++PDU
//-------[ConstructaSNMP++SNMPObject]---------------------------------------
Snmpsnmp(status);//CreateaSNMP++session
if(status!=SNMP_CLASS_SUCCESS){//checkcreationstatus
cout<<snmp.error_msg(status);//iffail,printerrorstring
return;}
status=snmp.trap(pdu,target,coldStart);
cout<<“TrapSendStatus=“<<snmp.error_msg(status);
};
@L_871_301@22.7.ReceivingTrapsExample
#include“snmp_pp.h”
//-----------------[trapcallbackfunctiondefinition]-------------------------------------------------------------------
voidmy_trap_callback(intreason,//reason
Snmp*session,//sessionhandle
Pdu&pdu,//trappdu
TimeTicks×tamp,//timestamp
SnmpTarget&target,//sourceofthetrap
void*cbd)//optionalcallbackdata
{
Address*address;
unsignedcharget_cummunity[80],set_community[80];
unsignedlongtimeout;
intretry;
if(reason==SNMP_CLASS_TRAP){
target.resolve_to_C(get_community,//getcommunity
set_community,//setcommunity
&address,//addressobject
timeout,//timeout
retry);//retry
cout<<“TrapReceivedfrom<<address->get_printable()<<“TrapId=“<<trapid.get_printable();
}
else
cout<<“TrapReceiveError=“<<session->error_msg(reason);
};
//---------------[trapreceiveregister]---------------------------------------------------------------------
Snmp*snmp;//dynamicSnmpobject
voidtrap_register()
{
//----------------[instantiateanSnmpobject,deletewhennolongerreceivingtraps]------------
intstatus;
snmp=newSnmp(status);
if((snmp==NULL)||(status!=SNMP_CLASS_SUCCESS))
cout<<“ErrorconstructingSnmpObject\n”;
else
{
//-------[setuptwoemptycollections,emptydenotesreceiveall]-------------------------------
TargetCollectiontargets;
OidCollectiontrapids;
//------[invoketheregsiter]----------------------------------------------------------------------------
if(status=snmp->notify_register(trapids,targets,&my_trap_callback))!=SNMP_CLASS_SUCCESS)
cout<<“SnmpTrapRegisterError“<<snmp->error_msg(status);
}
};
[Banker,Mellquist]
BankerKim,MellquistPeterE.,SNMP++,Connexions,TheInteroperabilityReport,Volume9,No.3,March1995.
[Comer]
Comer,DouglasE.,InternetworkingwithTCP/IP,Principles,ProtocolsandArchitecture,VolumeIPrenticeHall,1991.
[Gama,Helm,Johnson,Vlissides]
ErichGama,RichardHelm,RalphJohnson,JohnVlissides,DesignPatterns,AddisonWesley,1995.
[Meyers]
Meyers,Scott,EffectiveC++,1994.
[Petzold]
PetzoldCharles,ProgrammingMS-Windows,MicrosoftPress
[RFC1452]
J.Case,K.McCloghrie,M.Rose,S.Waldbusser,Coexistencebetweenversion1andversion2oftheInternet-standardNetworkManagementFramework,May03,1993.
[RFC1442]
J.Case,StructureofManagementInformationforversion2oftheSimpleNetworkManagementProtocol(SNMPv2),1993.
[Rose]
Rose,MarshallT.,TheSimpleBook,AnIntroductiontoInternetManagement,SecondEdition,PrenticeHallSeries1994.
[Rumbaugh]
Rumbaugh,James,Object-OrientedModelingandDesign,PrenticeHall,1991.
[Saks]
Saks,Dan,C++ProgrammingGuidelines,ThomasPlum&DanSacks,1992.
[Stallings]
Stallings,William,SNMP,SNMPv2andCMIPThePracticalGuidetoNetworkManagementStandards,1993.
[Stroustrup]
Stroustrup,Bjarne,TheC++ProgrammingLanguage,Edition#2AddisonWesley,1991.
[WinSNMP]
WinSNMP,WindowsSNMPAnOpenInterfaceforProgrammingNetworkManagementApplicationunderMicrosoftWindows.Version1.1.
[WinSockets]
WinSockets,WindowsSockets,AnOpenInterfaceforNetworkProgrammingunderMicrosoftWindows.