WinSNMP 库的 C++ 包装器






4.93/5 (22投票s)
2005年9月16日
8分钟阅读

522524

10719
一个用于在 Windows 上开发 SNMP 管理器(客户端)的 C++ 库。
引言
本文档演示了如何为 Windows API(在此例中为 WinSNMP 库)构建 C++ 包装器,以隐藏用户界面的复杂性。本文档中称为库的包装器旨在简化 WinSNMP 管理器(客户端)的开发,并利用 STL。请注意,本文档的目的不是提供有关 SNMP 或 WinSNMP API 本身的帮助,也不是提供一个功能齐全的库。为此,可以参考其他资源,例如 CodeProject 的其他文章或开源项目。
背景与动机
本文档的内容是我在对 STL 和 WinSNMP 库进行实验时,整理之前存储的一些代码的结果。撰写本文档的初衷只是为了与社区分享我的工作。
包含在示例文件中
文件包括完整的源代码(文本格式)和 UML 模型(Visio 格式),根据 GPL 许可分发,以及 VS 2005 Beta 2 项目文件。还包括已编译并运行的示例工具:SNMPGET、SNMPSET、SNMPWALK、SNMPTRAP 和 SNMPSCAN。
理解模型
全局概览
如果您了解 UML,可以通过查看图 1 的类图来在脑海中构建整体图景。
图 1 - UML 类图。
在此图中,所有库类都被表示出来,包括主要的类关系和公共方法。
SNMPManager 类
此类封装了 WinSNMP 的启动和关闭过程。要使用该库,您需要在执行任何其他操作之前调用管理器上的 startup
方法。可以通过 getManager
方法获取该管理器的唯一实例的指针(顺便说一下,这里可以看到单例模式的实际应用)。WinSNMP 和库的清理代码会在类析构函数中自动调用,该析构函数会在应用程序终止前被调用。getDisplayInformation
方法将返回一个字符串,其中包含有关已安装的 WinSNMP 库的各种信息项,例如版本、供应商和选项。
SNMPTracer 类
SNMPTracer
是一个单例类,用于控制协议消息的跟踪,可用于测试/调试目的(要查看其工作原理,请使用 -T 选项运行任何示例)。如果启用了跟踪(通过 enable
方法),在库运行期间,所有交换的 SNMP 协议数据单元的字符串表示形式将发送到控制台,包括时间戳。您可以浏览代码,了解如何通过 Win32 API 处理控制台。
SNMPObject 类
这是库中最有趣也是最有用的类。该类的实例代表 SNMP 数据项(或变量),包括寻址(OID)和/或值(用于读取或写入)。
OID
SNMPObject
的对象标识符可以通过 getOID
和 setOID
方法以字符串格式访问。所有解析和转换为二进制格式的操作都由内部处理。还提供了用于将 OID 与对象 OID 进行比较的帮助方法(compareOID
)。这些方法映射到 WinSNMP 库的词典式 OID 比较函数。
语法
语法方法(getSyntax
、setSyntax
和 getSyntaxAsString
)将以二进制或字符串形式返回或设置对象的内部类型。可用类型为:SNMP_INT
、SNMP_OCTETS
、SNMP_OPAQUE
、SNMP_BITS
、SNMP_CNTR64
、SNMP_CNTR32
、SNMP_GAUGE32
、SNMP_TIMETICKS
、SNMP_UINT32
、SNMP_OID
和 SNMP_IPADDR
。请注意,这些常量不一定与 WinSNMP 库中相应的常量相同。这样做的目的是构建一个包装器库,它不强制用户依赖于 WinSNMP 库本身。如果您打算在将来用另一个实现替换 WinSNMP 库,并希望避免重写用户代码,这种模式可能非常有用。
值
对象的值可以使用 getValueXXX
和 setValueXXX
方法设置或读取。基于字符串的方法尤其有用,因为它们提供了解析和生成任何类型值的代码。请检查内部代码,了解这是如何实现的。
显示信息
与其他库类一样,getDisplayInformation
返回一个包含人类可读信息的字符串,在本例中是 OID、值和语法。
SNMPSession 和 SNMPRemoteAgent 类
SNMPSession
类的对象保存有关一个或多个 SNMP 远程代理的信息。此时,此类并不十分重要,除非您了解 WinSNMP 库。您甚至不需要使用它,正如您在示例或 SNMPRemoteAgent
类的实现中所见。SNMPRemoteAgent
类的对象保存有关 SNMP 远程代理的信息。这包括名称(管理器机器的主机名或 IP 地址)、SNMP 社区名称和服务器远程端口。这些属性在类构造函数中设置。对于您需要与之交换信息的每个远程代理,都必须实例化一个 SNMPRemoteAgent
类的对象。
SNMP 请求
所有 SNMP 请求都使用 SNMPRequest
抽象类的实例执行。对于每种 SNMP 交换类型(Get、Set 或 Get Next),都存在一个具体子类,应根据您希望访问的 SNMP 服务来使用。要发出 SNMP 请求,您必须创建一个 SNMPRequest
对象并调用其 execute
方法。然后,您可以等待该对象,直到事务终止(通过 wait
方法),或者定期检查操作是否已完成(通过 isTerminated
方法)。实现本质上是异步的,并且不执行重试。可以通过 cancel
和 timedOut
/succeeded
/getErrorXXX
方法取消请求以及获取上次执行请求状态的结果信息。
Get 请求
可以通过实例化 SNMPRemoteAgentGetRequest
类来创建 Get 请求。构造函数接收要从中检索 OID 的 OID 和要从中请求对象的远程代理。要了解更多信息,请查看 SNMPGET 示例。
Set 请求
可以通过实例化 SNMPRemoteAgentSetRequest
类来创建 Set 请求。在这种情况下,输入的 SNMPObject
包括 OID 和要在服务请求中设置的值。要了解更多信息,请查看 SNMPSET 示例。
Get Next 请求
与 Get 请求类似,Get Next 请求(SNMPRemoteAgentGetNextRequest
)返回具有相邻 OID 的对象。要了解更多信息,请查看 SNMPWALK 示例。
SNMPTrap 类
SNMPTrap
类的处理方式与请求类非常相似,但允许您接收 SNMP 陷阱的指示。要使用它,请创建一个类实例,传入您希望监听的 OID 以及提供该 OID 的代理。然后调用 enable
方法开始接收指示。您也可以通过 disable
方法禁用指示。处理指示需要更多的工作,因为您需要派生 SNMPSession
类并覆盖 processTrap
方法。下面显示了一个使用示例,取自 SNMPTRAP 示例。
class MySession : public SNMPSession { public: virtual void processTrap(const SNMPObject & obj) { std::cout << obj.getDisplayInformation() << "\n"; } }; MySession session; SNMPRemoteAgent ragent(host, community, 0, &session); SNMPTrap trap(oid, &ragent); trap.enable();
请注意,陷阱处理尚未经过测试,因此可能存在问题。请随意检查它是否有效!
其他类
异常
您可以调用的绝大多数库方法(几乎所有方法)都可能抛出 SNMPException
或 SNMPErrorException
类的异常(实际上只抛出 SNMPErrorException
)。每个异常都会为您提供有关错误的详细信息,包括关于原因的消息和错误 ID。要打印此信息,请使用 toString
(如果您需要完整的异常堆栈,请使用 toStringStack
)。为了帮助编写库代码,使用宏(请参阅 SNMPException.h)设置了一个小型异常框架。
Sets
集合类(SNMPRequestSet
和 SNMPRemoteAgent
)非常直接,支持存储和集合操作。
Using the Code
对于那些认为代码和注释是最准确文档的人来说,下面将展示 SNMPGET 示例的完整代码,并附有其他注释。
int main(int argc, char* argv[]) { try { // startup SNMPManager::getManager()->startup(); // holds the host name or address of the agent std::string host = "172.18.200.90"; // holds the community name std::string community = "public"; // holds the response time out value for requests int tmo = 1000; // holds the agent port unsigned int port = 0; // zero means the SNMP default port // holds the number of OIDs to request int oidcount = 0; // holds the OIDs to request std::string oidarray[512]; // (...) here the command line arguments are parsed // to fill in the previous variables // create the remote agent SNMPRemoteAgent ragent(host, community, port); // create the SNMP objects containing the OIDs to request SNMPObject * oids = new SNMPObject[oidcount]; for(int i=0; i<oidcount; i++) { oids[i].setOID(oidarray[i]); } // create the get request SNMPRemoteAgentGetRequest getReq(oids, oidcount); // perform the request getReq.execute(&ragent); // wait for the response getReq.wait(tmo); // destroy request OIDs delete [] oids; // process result if(!getReq.succeeded()) { if(!getReq.timedOut()) { std::cout << getReq.getErrorAsString(); } else { std::cout << "timeout"; } } else { for(int i=0; i<getReq.getResultCount(); i++) { std::cout << getReq.getResult(i)->getDisplayInformation() << "\n"; } } std::cout << "\n"; return 0; } catch (SNMPException * pe) { // Process any errors std::cout << "\n\n"; std::cout << pe->toStringStack(); std::cout << "\n"; delete pe; } return 0; }
探索代码和示例
所有代码都包含在一组 *.h 和 *.cpp 文件中。考虑到文件名,找到您想要的类相当直接。示例包含在 main.cpp 文件中。要编译每个示例,您需要在文件开头解释的相应宏。
所有示例都是命令行工具,接受一组参数来执行各种操作。每个工具都包含一些通用选项,例如:打印帮助(-h 或 -?)、启用跟踪(-T)、设置超时(t:<n>)或设置代理的远程端口(p:<n>)。
- SNMPGET: 根据 OID 读取一组对象值。
- SNMPSET: 写入一个 SNMP 对象,提供其 OID、值,以及可选的语法。
- SNMPWALK: 显示代理中从给定 OID 开始的所有对象。
- SNMPSCAN: 扫描您的网络以检测 SNMP 代理的可用性。
- SNMPTRAP: 如果有效,则处理来自代理的陷阱。
最后
我希望本文档对您有所帮助,如果您认为有帮助,请发表评论。当然,在设计方面仍有很大的改进空间。虽然我没有计划进行任何更新,但欢迎您提出任何评论以及设计或编码方面的替代方案。