SNMP++2.8中文文档
SNMP++ 用C++构建的,处理简单网罗管理协议(SNMP)的API SNMP++.1 用C++构建的,处理简单网罗管理协议(SNMP)的API1 1.介绍...6 1.1.什么是SNMP++.6 1.2.SNMP++的本质...6 1.2.1.简单易用的SNMP++.6 1.2.2.编程安全的SNMP++.7 1.2.3.可移植的SNMP++.8 1.2.4.可扩充的SNMP++.8 2.一个介绍性的例子...9 2.1.一个简单的SNMP++例子...9 2.2.对介绍性例子的分析...9 3.SNMP++特性...10 3.1.完整的一套SNMPC++类...10 3.2.SNMP内存的自动管理...10 3.3.简单易用的...10 3.4.强大灵活的...10 3.5.可移植对象的...10 3.6.自动超时和重发机制...10 3.7.阻塞模式...11 3.8.异步的非阻塞模式...11 3.9.Notification、Trap的收发...11 3.10.通过双效的API支持SNMPv1和SNMPv2.11 3.11.支持SNMP的Get,GetNext,GetBulk,Set,Inform和Trap的操作...11 3.12.通过继承实现重定义...11 4.在MicrosoftWindows系列操作系统上使用SNMP++.12 4.1.WinSNMPVersion1.1的使用...12 4.2.对IP和IPX的支持...12 4.3.对Notification、Trap收发的支持...12 4.4.与HPOpenViewforWindows兼容...12 5.在UNIX上使用SNMP++.13 5.1.统一的类的接口...13 5.2.Windows到UNIX的仿真与移植...13 5.3.与HPOpenViewforUNIX兼容...13 6.SNMPSyntaxClasses.14 7.ObjectIdClass.15 7.1.对象标识符类...15 7.2.OidClass的成员函数列表...15 7.3.一些OidClass的例子...16 8.OctetStrClass.19 8.1.八位字节类...19 8.2.OctetStrClass的成员函数列表...19 8.3.注意...20 8.4.一些OctetStrClass的例子...21 9.TimeTicksClass.22 9.1.时间戳类...22 9.2.TimeTicksClass的成员函数列表...22 9.3.注意...22 9.4.一些TimeTicksClass的例子...23 10.Counter32Class.24 10.1.32位计数器类...24 10.2.Counter32Class的成员函数列表...24 10.3.一些Counter32Class的例子...24 11.Gauge32Class.26 11.1.容量类...26 11.2.Gauge32Class的成员函数列表...26 11.3.一些Gauge32的例子...26 12.Counter64Class.28 12.1.64位计数器类...28 12.2.Counter64Class的成员函数列表...28 12.3.一些的Counter64Class例子...29 13.AddressClass.30 13.1.什么是网络地址类?...30 13.2.为什么要使用网络地址类?...30 13.3.Addressclass.30 13.4.AddressClasses及其接口...30 13.5.IpAddressClass的特点...32 13.6.GenAddress的特点...32 13.7.AddressClass的有效性...32 13.8.UdpAddresses和IpxSockAddresses.33 13.8.1.用UdpAddresses发送请求...33 13.8.2.用IpxSockAddresses发送请求...33 13.8.3.用UdpAddress和IpxSockAddress接收Notification.33 13.9.有效的地址格式...33 13.10.AddressClass例子...34 14.TheVariableBindingClass.36 14.1.VariableBindingClass成员函数列表...36 14.2.VbClass的公有成员函数...37 14.2.1.VbClass的构造和析构函数...37 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 14.2.9.Vb对象的成员函数:GetSyntax.41 14.2.10.检查Vb对象的有效性...42 14.2.11.把Vb对象付给另一个Vb对象...42 14.2.12.Vb对象的错误信息...42 14.3.VbClass例子...42 15.PduClass.45 15.1.PduClass成员函数列表...45 15.2.PduClass的构造和析构...46 15.3.访问Pdu的成员函数...46 15.4.PduClass重载操作符...47 15.5.PduClass处理Traps和Informs的成员函数...47 15.6.加载Pdu对象...48 15.7.加载Pdu对象...48 15.8.卸载Pdu对象...49 16.SnmpMessageClass.50 17.TargetClass.51 17.1.抽象的Target51 17.2.Target地址...51 17.3.重发机制...51 17.4.TargetClass接口...51 17.5.CTargetClass(以Community为基础的Target)52 17.5.1.CTarget对象可通过3种不同的方式构建...53 17.5.2.修改CTargets.53 17.5.3.访问CTargets.53 17.5.4.CTargets例子...54 18.SnmpClass.55 18.1.SnmpClass成员函数列表...55 18.2.双效的API56 18.3.SnmpClass的公共成员函数...57 18.3.1.SnmpClass的构造和析构函数...57 18.3.2.SnmpClass构造函数...57 18.3.3.SnmpClass析构函数...57 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.SnmpClass的异步方式成员函数...58 18.4.1.SNMP++异步回调函数的类型定义...58 18.4.2.取消一个异步请求...59 18.4.3.SnmpClass的异步成员函数:Get59 18.4.4.SnmpClass的异步成员函数:Set60 18.4.5.SnmpClass的异步成员函数:GetNext60 18.4.6.SnmpClass的异步成员函数:GetBulk.60 18.4.7.SnmpClass的异步成员函数:Inform..60 18.5.SNMP++通知的方法...60 18.5.1.发送Trap.61 18.5.2.接收Notification.62 18.5.3.使用OidCollection,TargetCollection和AddressCollections过滤...63 18.6.SNMP++Class返回的错误号...64 18.6.1.SnmpClass的错误消息成员函数...64 19.运行模式...65 19.1.MicrosoftWindows事件驱动系统的运作...65 19.2.OpenSystemsFoundation(OSF)X11Motif的运作...65 19.3.不以GUI为基础的应用的运作...65 20.状态&错误编号...67 21.错误状态值...68 22.SnmpClass例子...69 22.1.GettingaSingleMIBVariableExample.69 22.2.GettingMultipleMIBVariablesExample.69 22.3.SettingaSingleMIBVariableExample.71 22.4.SettingMultipleMIBVariablesExample.71 22.5.WalkingaMIBusingGet-NextExample.72 22.6.SendingaTrapExample.73 22.7.ReceivingTrapsExample.73 23.参考书目...75
1.介绍 目前有许多可以创建网络管理应用的SNMP的API。大多数API都提供了一个很大的函数库,调用这些函数的程序员需要熟悉SNMP内部的工作原理和它的资源管理机制。这些API大多都是平台相关的,导致了SNMP的代码也成了操作系统相关的或者网络系统平台有关的,难以移植。另一方面由于C++有丰富的、可复用的标准类库,用C++开发应用成了目前的主流,然而C++标准类库所缺少的正是一套封装好的处理网络管理的类。如果基于面向对象的方法来进行SNMP网络编程,可以提供以下诸多好处:易用、安全、可移植、能扩展。因此SNMP++灵活有效的解决了其他类似API执行和管理起来都很痛苦的问题。 1.1.什么是SNMP++ SNMP++是一套C++类的集合,它为网络管理应用的开发者提供了SNMP服务。SNMP++并非是现有的SNMP引擎的扩充或者封装。事实上为了效率和方便移植,它只用到了现有的SNMP库里面极少的一部分。SNMP++也不是要取代其他已有的SNMPAPI,比如WinSNMP。SNMP++只是通过提供强大灵活的功能,降低管理和执行的复杂性,把面向对象的优点带到了网络编程中。 1.2.SNMP++的本质 1.2.1.简单易用的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++初步的理解。 1.2.2.编程安全的SNMP++ 大多数SNMPAPI需要程序员去管理大量的资源。不恰当的装载或卸载这些资源,会导致内存崩溃或泄漏。SNMP++提供的安全机制,可以实现对这些资源的自动管理。SNMP++的用户可以体验到自动管理资源与对话所带来的好处。SNMP++在编程上的安全突出表现在下面的领域: 1.2.2.1.为SNMP资源提供安全的管理 这包括对SNMP的结构、会话以及传输层的管理。SNMPclass被设计成所谓的抽象数据类型(ADT),隐藏了私有数据,而通过提供公有的成员函数来访问或修改这些隐藏了的实例变量。 1.2.2.2.提供查错、自动超时重发的机制 SNMP++的用户不需要关心如何为不可靠的网络传输机制提供可靠性。可能出现的通信错误包括:数据包丢失、数据包重复以及反复提取数据包。SNMP++消除了所有这些问题出现的可能性,为用户提供了传输层的可靠性。 1.2.3.可移植的SNMP++ SNMP++的主要目的之一就是提供一套可移植的API,进而穿越各种操作系统(Os)、网络系统(NOS)以及网络管理平台。由于SNMP++隐藏了内部机制,所以从各个平台的角度来看SNMP++的公用接口都是一样的。使用SNMP++的程序员不需要为平台迁移去修改代码。另一个移植方面的问题是在多种协议上运行的能力。目前,SNMP++能运行在IP协议和IPX协议上,或者两者都可以。 1.2.4.可扩充的SNMP++ 扩充不应该只是多一种选择,而是更深层次的。SNMP++不仅是可扩充,而且是很容易扩充。SNMP++的扩充囊括了对下列领域的支持:新的操作系统、网络系统、网络管理平台、网络协议、SNMPv2及其新特性。通过派生C++的类,SNMP++的用户可以根据自己的喜好继承、重载。 1.2.4.1.重载SNMP++的基础类 应用的开发者可以通过派生出SNNP++的子类来提供所需的操作和属性,这正是面向对象的核心主题。SNMP++的基础类被打造成通用的、没有包含任何具体的数据结构和操作。通过C++派生类以及重新定义虚函数,可以很容易的添加新属性。
2.一个介绍性的例子 在开始介绍SNMP++的各种特性之前,这里先举个简单的例子来展现它的强大和简单。该例子是从指定的代理端上获取SNMPMIB的系统描述符(SystemDescriptorobject)。包含了创建一个SNMP++会话、获取系统描述符,并打印显示出来的所需的所有代码。其中重发和超时机制已经被SNMP++自动管理了。以下属于SNMP++的代码,采用粗体显示。 2.1.一个简单的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! 2.2.对介绍性例子的分析 真正属于SNMP++的语句就10行代码。首先用代理端的IP地址建立一个CTarget对象;然后用MIB对象所定位的系统描述符创建一个变量绑定(Vb);接着就把这个Vb纳入一个Pdu对象;最后生成一个Snmp对象来执行SNMP的get操作。一旦找到了所需的数据,对应的应答消息就被打印出来。另外,所有的处理错误代码也都包含在内了。
3.SNMP++特性 3.1.完整的一套SNMPC++类 SNMP++是以一套C++类作为基石的。这些类是:对象描述符(Oid)类、变量绑定(Vb)类、协议数据单元(Pdu)类、Snmp类。并且,其他各种用抽象语法表示(ASN.1)来描述的管理信息结构(SMI),也被抽象成了简单的、面向对象的类型。 3.2.SNMP内存的自动管理 当SNMP++的对象被实例化或销毁的时候,其相关的类可以自动管理着各种各样的SNMP结构和资源。这就使得应用的开发者不用再担心数据结构和资源的卸载,不然就得为防止内存的崩溃或者泄漏提供有效的保护措施。SNMP++的对象的实例化可以是静态的,也可以是动态的。静态的实例化可以在对象脱离它的作用域时卸载掉;动态分配则需要使用C++的new和delete。在SNMP++内部,有许多被隐藏和保护在公用接口后面的SMI结构。所有的SMI结构都是在内部管理的,程序员不需要定义或管理SMI的结构和它的值。因为在SNMP++内绝大部分地方是不存在C的指针的。 3.3.简单易用的 由于隐藏并管理了所有SMI结构和它们的值,SNMP++的类使用起来即简单又安全。外部程序员无法破坏到隐藏和保护在作用域后面的东东。 3.4.强大灵活的 SNMP++提供了强大灵活的功能,降低了管理和执行的复杂性。每个SNMP++对象都通过建立一个会话来和一个代理端联系。即由一个SNMP++的对话类的实例,就能处理所有与特定代理端的连接。另外自动重发和超时控制的机制,为每个SNMP++对象都带来了可靠性。一个应用可能会包含许多SNMP++的对象的实例,每个实例都可能与相同或不同的代理端通话。有了这个功能强大的特性,网络管理程序就可以为每个管理单元建立起不同的会话。另一方面,就算单一的SNMP会话也可以解决问题。例如:一个应用可以通过一个SNMP++对象来处理图形统计,另一个SNMP++对象监控trap,也许还有第三个SNMP++对象用以浏览SNMP。SNMP++自动并行处理了同一时刻来自不同SNMP++实例的请求。 3.5.可移植对象的 SNMP++的主体是可以移植的C++代码。其中只有SnmpClass的实现与不同的目标操作系统有关。如果你的程序中包含了SNMP++的代码,那么导出这部分代码的时候,就可以不做任何修改。 3.6.自动超时和重发机制 SNMP++提供了自动超时和重发机制,程序员不用去实现超时或重发机制的代码。重发机制是在SnmpTargetClass里面定义的,这就使得每一个目标(Target)都具有了它自己的超时/重发机制。 3.7.阻塞模式 SNMP++提供了阻塞方式。MS-Windows上的阻塞方式可以并发的阻塞从每个SNMP类的实例发出的请求。 3.8.异步的非阻塞模式 SNMP++还为应答提供了异步的非阻塞的方式。超时和重发机制同时支持阻塞和异步两种模式。 3.9.Notification、Trap的收发 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++的成员函数使用相同的参数表,也都支持阻塞和非阻塞(异步)方式。 3.12.通过继承实现重定义 SNMP++是用C++实现的,所以允许程序员重载或重定义那些不适合他们的操作。举个例子:如果一个应用需要特定的Oid对象,那就需要建立一个OidClass的子类,用以继承所有Oid类的属性和操作,同时在派生类种加入新的属性和操作。
4.在MicrosoftWindows系列操作系统上使用SNMP++ SNMP++已经在MS-Windows3.1,MS-WindowsForWorkGroups3.11,MS-WindowsNT3.51,andMS-Windows’95上实现了。 4.1.WinSNMPVersion1.1的使用 在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的功能。 4.4.与HPOpenViewforWindows兼容 已经有大量使用SNMP++创建的应用,实现了HPOpenViewforWindows的兼容。
5.在UNIX上使用SNMP++ 5.1.统一的类的接口 用在UNIX设备上的SNMP++类的接口和MS-Windows是一样的。 5.2.Windows到UNIX的仿真与移植 通过编译、连接对应的SNMP++类,SNMP++就可以实现在UNIX上运行。SNMP++/UNIX的设计决定了它可以同时运行在原始的UNIX字符模式、X-Window模式,或者Windows-to-UNIX的仿真工具上。 5.3.与HPOpenViewforUNIX兼容 已经有大量使用SNMP++创建的应用,实现了与HPOpenViewforUNIX的兼容。
6.SNMPSyntaxClasses SNMP++之SNMPSyntax的对象模型(ObjectModelingTechnique)视图 SNMP++的SNMPsyntaxclasse描绘了一个具有C++面向对象风格的视图。即用于描述SNMP的SMI之ASN.1的数据类型视图。它包含了映射到对应的SMI类型的一组类的集合。而且为了方便使用,还引入了一些非SMI的类。SNMP++为这些SNMP数据类型提供了强大、简单易用的接口。下表概要地描述了各种SNMP++syntaxclasses:
7.ObjectIdClass SNMP++之OidClass的对象模型(ObjectModelingTechnique)视图 7.1.对象标识符类 对象标识符类(Oid)封装了SMI的对象标识。信息管理库(MIB)中所定义的SMI的对象是一种在MIB中找到的数据元素的数据标识。与SMIOid相关的结构和函数,自然都是面向对象的。事实上Oidclass与C++的Stringclass有许多共同之处。如果你熟悉C++的Stringclass或者MFC的CStringclass,那么你就会感觉Oidclass用起来很亲切、简单。Oidclass被设计成了快速有效的类;它可以定义和操作对象标识;不依赖现有的SNMPAPI,完全是可移植的;可以在任何ANSIC++编译器上进行编译。 7.2.OidClass的成员函数列表
7.3.一些OidClass的例子 下面的例子展示了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)); } }
8.OctetStrClass SNMP++之OctetStrClass的对象模型(ObjectModelingTechnique)视图 8.1.八位字节类 通过SNMP++的Octetclass,可以简单且安全地操作SMI的8位字节。有了Octetclass,就不需要通过内部指针和长度来操作8位字节了。使用SNMP++的Octetclass来实例化、操作、销毁一个8位字节对象是很简单的,不用担心如何管理内存以及内存是否会泄漏。与ANSIC++的stringclass类似,OctetStrclass可以通过多种方法构造8位字节,还可以对它们进行赋值操作,与其他SNMP++classes一起使用。 8.2.OctetStrClass的成员函数列表
8.3.注意 当输出一个OctetStr对象时,如果该8位字节所包含的字符不是ASCII码,对成员函数char*或者get_printable()的调用,就会自动转换成对成员函数get_printable_hex()的调用。这就使得使用者只需要简单地使用成员函数char*或get_printable()来进行输出。而成员函数get_printable_hex()是专门用来把OctetStr按16进制格式输出的。 8.4.一些OctetStrClass的例子
9.TimeTicksClass SNMP++之TimeTicksClass的对象模型(ObjectModelingTechnique)视图
9.1.时间戳类 SNMP++的TimeTicksClass为使用SMI中的timeticks带来了方便。SMI的时间戳被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMItimeticks被加工成了一种特殊的类型。因此SNMP++的TimeTicks类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到TimeTicks的对象上一样有效。TimeTicksclass与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,TimeTicks的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMItimeticks,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。 9.2.TimeTicksClass的成员函数列表
9.3.注意 TimeTicks对象用TimeTicks::get_printable()输出时,其值自动被格式化为“DDdays,HH:MM:SS.hh”。其中DD代表天,HH代表小时(24时制的),MM代表分钟,SS是秒钟,hh则是百分之几秒。 9.4.一些TimeTicksClass的例子 //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
10.Counter32Class SNMP++之Counter32Class的对象模型(ObjectModelingTechnique)视图 10.1.32位计数器类 当需要用到SMI中的32位计数器时,SNMP++的Counter32Class为之带来了方便。SMI的计数器被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMIcounters被加工成了一种特殊的类型。因此SNMP++的Counter32类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到Counter32的对象上一样有效。Counter32class与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,Counter32的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMIcounter,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。 10.2.Counter32Class的成员函数列表
10.3.一些Counter32Class的例子 //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
11.Gauge32Class SNMP++之Gauge32Class的对象模型(ObjectModelingTechnique)视图
11.1.容量类 SNMP++的Gauge32Class为使用SMI中的timeticks带来了方便。SMI的容量被定义成了一种存放无符号长整形的存储单元。为了成为无符号长整形,SMIgauges被加工成了一种特殊的类型。因此SNMP++的Gauge32类具有无符号长整形的所有功能和属性,但同时又是一个独立的类。对无符号长整形的任何操作,拿到Gauge32的对象上一样有效。Gauge32class与其他SNMP++的类,比如Vbclass交互的时候,还可以有些额外的操作:在使用Vbclass的时候,TimeTicks的对象可以被置入Vb对象(用Vb::set),也从Vb对象中取出(用Vb::get)。也即,对于SMIgauge,开发者可以像对无符号长整形一样来操作,并且还提供了一对一的映射关系。 11.2.Gauge32Class的成员函数列表
11.3.一些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
12.Counter64Class SNMP++之Counter64Class的对象模型(ObjectModelingTechnique)视图
12.1.64位计数器类 SNMP++的64bitcounterclass实现了SMI的64bitcounters。64位计数器是在SNMPv2中定义的一种变量,所以在SNMPv1中并不存在这种MIB变量。64bitcounters由两个无符号长整形(一高位、一低位)组成,Counter64class很好的实现了它。因为Counter64class提供了加减乘除操作符的重载,所以它使用起来感觉很自然。 12.2.Counter64Class的成员函数列表
12.3.一些的Counter64Class例子 //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_c64n”; if(c64!=my_c64)//overloadednotequaltest cout<<“c64notequaltomy_c64n”; if(c64<my_c64)//overloadedlessthan cout<<“c64lessthanmy_c64n”; };//endCounter64example
13.AddressClass SNMP++之AddressClass的对象模型(ObjectModelingTechnique)视图 13.1.什么是网络地址类? 网络地址类是一组C++类的集合,它提供了简单、安全、可移植、高效地使用网络地址的方法。许多网络管理应用需要通过网络地址来访问和管理设备,包括地址的确认、更改,以及用户接口的分配。Addressclass不但管理了所有指定的网络地址的内部细节,而且还通过封装和隐藏其内部机制,让得到解放的开发应用的程序员可以专注于解决实际问题。开发Addressclass的动机来源于95年InteropSNMP++Birds-of-A-Feather(BOF)上的讨论以及与Hewlett-PackardOpenView程序员的交流。 13.2.为什么要使用网络地址类? 地址类提供了以下好处:自动内存管理、地址确认、移植到任何C++环境、简单易用,及可扩充性。目前的Addressclass由4个子类组成:IpAddressClass,IpxAddressClass,MacAddressclass和GenAddressclass。将来也许会有其他的子类加入,比如IPNextGeneration(IPng)。 13.3.Addressclass 所有地址类都派生自同一个抽象基类:Addressclass。它是一个抽象类,即这个类不会产生实例对象。Addressclass通过使用虚成员函数,提供了公用接口。也就是说可以使用公用接口调用各个不同地址类的函数。这样的结果是:当需要修改使用了地址类的模块时,需要改动的代码就很少了。 13.4.AddressClasses及其接口 作为基类的AddressClasses是一个抽象类,它囊括了所有子类的通用操作。也即包含了以下统一的接口:构造、访问、修改地址。
13.5.IpAddressClass的特点 IpAddressClass可以通过调用成员函数Address::get_printable()自动以DNS显示出来。如果没有激活DNS或者无法识别地址,则返回以点号分割的字符。另一方面,一个IpAddress可以用一个友好的名字(字符串,而非以点号分割的数字)来构造,这样构造函数就可以激活DNS的显示。如果这个名字没被找到,那么该地址也就是无效的。这个强大的功能允许你在对外表现时,使用友好的名字方式。 13.6.GenAddress的特点 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”; 13.7.AddressClass的有效性 所有地址类都支持成员函数::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就允许定义端口和套接字的信息。 13.8.1.用UdpAddresses发送请求 当向一个使用非标准默认端口的代理端发送请求信息时,就需要用到UdpAddressesclass了。UdpAddressesclass提供了两个成员函数分别来设置和获取自定义的端口信息。用一个加载了UdpAddresses的目标来发送请求,就可以实现SNMP++对自定义端口的使用。 13.8.2.用IpxSockAddresses发送请求 当向一个使用非标准默认IPX套接字的代理端发送请求信息时,就需要用到IpxSockAddressesclass了。IpxSockAddresses提供了两个成员函数分别来设置和获取自定义的IPX套接字信息。用一个加载了IpxSockAddress的目标来发送请求,就可以实现SNMP++对自定义套接字的使用。 13.8.3.用UdpAddress和IpxSockAddress接收Notification UdpAddress和IpxSockAddress还可以通过指定需要修改的端口和套接字来接收notification。即允许应用通过非标准的端口和套接字来接收trap和inform。 13.9.有效的地址格式 目前的有效地址格式定义如下: 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:‘:’ 13.10.AddressClass例子 //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
14.TheVariableBindingClass 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成员函数列表
14.2.VbClass的公有成员函数 Vbclass提供了许多公有成员函数来访问和修改Vb对象。 //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); 14.2.4.用一个GenAdress对象设置value //setanGenAddressobjectasavalue voidVb::set_value(constGenAddressgenaddr); 14.2.5.用一个UdpAdress对象设置value //setanUdpAddressobjectasavalue voidVb::set_value(constUdpAddressudpaddr); 14.2.6.用一个IpxSockAdress对象设置value //setanIpxSockAddressobjectasavalue voidVb::set_value(constIpxSockAddressipxsockaddr); 14.2.7.用一个Octet对象设置value部分 //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);
从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); 14.2.9.Vb对象的成员函数:GetSyntax 该函数并未遵循面向对象规则。如果要知道对象代表的事物,可以通过该函数返回对象内部的id,但同时也破坏了内部数据的隐藏。如果不考虑数据隐藏的话,有些时候可能还是需要知道Vb内部的value,以便抽取出那些隐藏的value。比如,当实现一个浏览器时需要获取Vb,询问Vb有什么数据并取出Vb包含的数据。该操作所返回的syntaxvalues就是SMIsyntaxvalue。 //returnthecurrentsyntax //ThismethodviolatestheOOparadigmbutmaybeusefulif //thecallerhasaVbobjectanddoesnotknowwhatitis. //Thiswouldbeusefulintheimplementationofabrowser. SmiUINT32get_syntax(); 14.2.10.检查Vb对象的有效性 通过调用成员函数Vb::valid()可以检查一个Vb对象的实例的有效性。有效的Vb是那些已经获得了Oid的。 //determineifaVbobjectisvalid intVb::valid(); 14.2.11.把Vb对象付给另一个Vb对象 通过重载赋值操作符“=”,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的实际值或者错误值。
14.3.VbClass例子 下面的例子展示了使用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<<“xequalsyn”; //setandgetlongints longinta,b; a=100; //-------[waystosetandgetvalues] if(a==b)cout<<“aequalsbn”; //set&getunsignedlongints unsignedlongintc,d; c=1000; vbs[0].set_value(c);vbs[0].get_value(d); if(c==d)cout<<“cequalsdn”; //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<<“o1equalso2n”; //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=%sn”,good_beer); //getandsetanipanaddress IpAddressipaddress1,ipaddress2; ipaddress1=“10.4.8.5”; vbs[5].set_value(ipaddress1); vbs[5].get_value(ipaddress2); cout<<ipaddress2; }//endvbexample
15.PduClass 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成员函数列表
15.2.PduClass的构造和析构 有多种方法构造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(); 15.4.PduClass重载操作符 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); 15.6.加载Pdu对象 为了在管理应用中使用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); 15.7.加载Pdu对象 为了在管理应用中使用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 } 15.8.卸载Pdu对象 从阻塞或异步请求中得到请求的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 };
16.SnmpMessageClass SnmpMessageClass允许对SNMP++对象使用抽象编码规则(ASN.1)和基础编码规则(BER)来编码和解码,进而生成可以在线路上传送的SNMP消息。该class可以方便的串行化Pdu对象,以便于后期的各种使用。大多数SNMP++的用户不需要使用这个类,因为Snmpclass已经完成了这项任务,包括管理超时和重发。但是如果程序员想对消息编码,这里也为其提供一种选择,例如很多代理系统就在使用它们自己的传输层。SnmpMessageclass提供的各种成员函数如下表所示:
17.TargetClass Targetclass是一个C++类,在SNMP++中用它来定义和使用target。一个target在SNMP通讯中,可以想象成一个代理端的管理层的概念,它由多个网络地址组成。Targets包含了重发和超时机制的信息,还有SNMP协议类型(SNMPv1和SNMPv2)等等。目前已有的Targets唯一的子类是Community-basedCTarget。CTargetclass可用在SNMPv1和SNMPv2的通讯上,由此可以重用你已有的代码到SNMPv2通讯中,不需要做修改。通过它,还可以使得一个SNMP++会话与某个特定的代理端的属性无关。 17.1.抽象的Target SNMP++支持抽象Target的概念。由该抽象Target可以操作所有实际的Target派生类。所有使用Target的SNMP++成员函数接收的都是抽象Target,而不是特指的派生Target对象。当需要支持新的Target时,这种抽象的接口可以减小代码的改动。 17.2.Target地址 每个target都与一个地址对象(Addressobject)相关联。该地址是一个GenAddress,因此可以处理所有SNMP++地址(IP,IPX或其他)。为指明被管理的代理端地址并与一个Target相关联,只需要简单地通过构造函数的参数或成员函数就可实现。 17.3.重发机制 每个Target都具有重发机制,在该机制中定义了超时和重发。由该重发机制可指定等待一个SNMP应答的周期,以及当没有收到一个SNMP应答时进行多少次重发。超时的最小单位被定义成百分之一秒,即当取值为100代表每个应答等待1秒。重发时记录了重发的次数,注意,第一次请求不属于重发,只是发送。所以重发值取3,表示当等待一个应答时最多可以重发3次。等待的总时间可以用下列式子计算:TotalWaitTime=time-out*(retry+1) 如果一个SNMP++应答没有在上式所计算出来的等待总时间内到来,将会返回一个SNMP++超时的错误号。该操作在阻塞和异步两种调用中都可使用。 17.4.TargetClass接口
17.5.CTargetClass(以Community为基础的Target) CTargetclass允许显示地定义以Community为基础的Target。一个CTarget用以SNMPCommunity为基础的Target定义了一个SNMP代理端。这包含了“读权限、写权限”的communitynamesandanaddress。地址是用SNMP++Addressclass来表示的,所以该地址可以是IP或者IPXaddress(Addressclass是个抽象基类,所以可以实现多态操作)。CTargetclass使用前提应该是:应用开发者明确地知道代理端所支持的以SNMPcommunity为基础的访问方式,即SNMPv1或SNMPv2。 17.5.1.CTarget对象可通过3种不同的方式构建 //----------[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”); 17.5.3.访问CTargets //-----[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”; 17.5.4.CTargets例子 //------------[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成员函数列表
18.2.双效的API 所有的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)。 18.4.2.取消一个异步请求 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 18.5.SNMP++通知的方法 SNMP++API支持收发trap的成员函数 18.5.1.发送Trap 发送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的描述一致。 18.5.2.接收Notification 接收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
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派生来的。统一的集合操作如下:
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++时,可返回多种错误编号。这些错误号可穿越平台,进而帮助应用的开发者发现并检查错误条件。 18.6.1.SnmpClass的错误消息成员函数 如果在使用Snmp成员函数过程中出现了一个错误,成员函数Snmp::error_msg()可以用来检索出一个友好的错误字符串。 //------------------------[errormessage]----------------------------- char*Snmp::error_msg(constintstatus);//returnsstringforprovidedstatus
19.运行模式 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()的调用返回 ·如果对X11注册成功,则该函数返回零 //----------------[initializeSNMP++X11Context]-------------------------- intSNMPX11Initialize(XtAppContextcontext); 19.3.不以GUI为基础的应用的运作 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()以打印出该错误的文本描述。
21.错误状态值 当SNMP++的成员函数返回值是“SNMP_CLASS_ERR_STATUS_SET”时,可以由成员函数Pdu::get_error_status()获取一个额外的错误状态。该值表示的是RFC1905中实际的SMIPDU错误状态值。这些值可以传进成员函数Snmp::err_msg()以友好的方式描述。
22.SnmpClass例子 关于这个部分的附加例子,请查阅下表所列的文档,以获得可用作命令的完整实用程序。
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
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); } }; 22.6.SendingaTrapExample #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); }; 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<<“ErrorconstructingSnmpObjectn”; 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); } };
23.参考书目 [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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |