65.9K
CodeProject 正在变化。 阅读更多。
Home

#SNMP 入门:一个开源 SNMP 实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (17投票s)

2012 年 10 月 1 日

MIT

4分钟阅读

viewsIcon

200670

downloadIcon

12433

本文介绍了 #SNMP 及其使用方法,包括如何利用它来完成 SNMP 操作,例如管理支持 SNMP 的设备。

引言

#SNMP (SharpSNMP) Suite 是一套免费的 SNMP 工具,基于开源库,专为以 Microsoft .NET/Xamarin Mono 平台为目标的开发者而设计。它采用 C# 开发,也可用于 VB.NET、Delphi Prism 和许多其他编程语言。

本文在 MIT 许可下发布(因此本文所示示例代码也在此许可下发布)。

背景 

.NET Framework 从一开始就完全支持基于 TCP/IP 的套接字编程。然而,由于 .NET Framework 基类库中没有专门针对 SNMP 的类,开发人员不得不依赖非常昂贵的三方库。市面上也有一些免费解决方案,但它们要么缺乏 SNMP v3、MIB 支持或其他高级功能。我在 2007 年的一篇博文中列出了更多信息,如果您想深入了解。

2008 年 4 月,我发布了一个名为 #SNMP 的开源项目来解决这个问题,因为我相信通过协作可以实现更好的解决方案,从而惠及所有需要足够好的免费解决方案的人。经过 4 年多的发展,该库已发展到目前的规模,拥有足够强大的库和许多有用的示例项目。

项目主页位于 CodePlex,源代码位于 GitHub。请注意,代码库被拆分成不同的模块,并在不同的许可下发布,正如 KB600012 中所述。

#SNMP 主要可在 Windows/.NET 平台上使用,例如 Windows XP/Windows Vista/Windows 7 和 Windows Server 操作系统,支持 .NET Framework 3.5/4.0/4.5。作为纯 .NET 代码库,它已成功移植到 Windows CE/.NET CF、Mono、MonoTouch 以及 Mono for Android。

使用库

文档包包含一个 SandCastle 生成的帮助文件,可用于快速浏览 #SNMP 库(Lextm.SharpSnmpLib.*.dll)中提供的所有类。

以下是将一些 SNMP 操作(GET、SET 等)转换为 #SNMP 函数调用的示例:

GET 操作

以下代码展示了如何向位于 192.168.1.2 的 SNMP 代理发送 SNMP v1 GET 消息,并查询 OID 1.3.6.1.2.1.1.1.0,

var result = Messenger.Get(VersionCode.V1, 
                           new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161), 
                           new OctetString("public"),
                           new List<Variable>{new Variable(new ObjectIdentifier("1.3.6.1.2.1.1.1.0"))},
                           60000);

如果在 60 秒(1 分钟)内未收到回复,此操作将超时并引发异常(TimeoutException)。如果发生任何错误,则可以捕获 ErrorException。所有 #SNMP 异常都继承自 SnmpException

返回的结果是一个列表,与发送的 Variable 对象列表匹配。此列表中的 Variable 包含 OID 的值。

SET 操作

以下代码展示了如何向位于 192.168.1.2 的 SNMP 代理发送 SNMP v1 SET 消息,并将 OID 1.3.6.1.2.1.1.6.0 的值设置为“Shanghai”,

var result = Messenger.Set(VersionCode.V1, 
                           new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161), 
                           new OctetString("public"),
                           new List<Variable>{new Variable(new ObjectIdentifier("1.3.6.1.2.1.1.6.0"), new OctetString("Shanghai"))},
                           60000);

GET-NEXT 操作

以下代码展示了如何向位于 192.168.1.2 的 SNMP 代理发送 SNMP v1 GET-NEXT 消息,并查询 OID 1.3.6.1.2.1.1.1.0,

GetNextRequestMessage message = new GetNextRequestMessage(0,
                              VersionCode.V1,
                              new OctetString("public"),
                              new List<Variable>{new Variable(new ObjectIdentifier("1.3.6.1.2.1.1.6.0"))});
ISnmpMessage response = message.GetResponse(60000, new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161));
if (response.Pdu().ErrorStatus.ToInt32() != 0) 
{
    throw ErrorException.Create(
        "error in response",
        receiver.Address,
        response);
}

var result = response.Pdu().Variables;

GET-BULK 操作

以下代码展示了如何向位于 192.168.1.2 的 SNMP 代理发送 SNMP v2 GET-BULK 消息,并查询 OID 1.3.6.1.2.1.1.1.0,

GetBulkRequestMessage message = new GetBulkRequestMessage(0,
                      VersionCode.V2,
                      new OctetString("public"),
                      0,
                      10,
                      new List<Variable>{new Variable(new ObjectIdentifier("1.3.6.1.2.1.1.6.0"))});
ISnmpMessage response = message.GetResponse(60000, new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161));
if (response.Pdu().ErrorStatus.ToInt32() != 0)
{
    throw ErrorException.Create(
        "error in response",
        receiver.Address,
        response);
}

var result = response.Pdu().Variables;

Walk 操作

Walk 不是一个原子操作。这意味着它利用了几个 GET-NEXT(SNMP v1 walk)或 GET-BULK(v2 及以上版本)操作。以下代码展示了如何在位于 192.168.1.2 的 SNMP 代理上从 1.3.6.1.2.1.1 开始执行 walk 操作,

var result = new List<Variable>();
Messenger.Walk(VersionCode.V1, 
               new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161), 
               new OctetString("public"), 
               new ObjectIdentifier("1.3.6.1.2.1.1"), 
               result, 
               60000, 
               WalkMode.WithinSubtree);

返回的结果包含此 SNMP 代理中位于 1.3.6.1.2.1.1 树节点下的所有可用 OID(作为 Variable)的列表。

#SNMP 支持两种 walk 模式:DefaultWithinSubtree

Messenger.Walk 是基于 GET-NEXT 构建的。请注意,如果设备支持 SNMP v2,则应使用 Messenger.BulkWalk,因为它基于 GET-BULK 构建并提供更好的性能。

var result = new List<Variable>();
Messenger.BulkWalk(VersionCode.V2, 
                   new IPEndPoint(IPAddress.Parse("192.168.1.2"), 161), 
                   new OctetString("public"), 
                   new ObjectIdentifier("1.3.6.1.2.1.1"), 
                   result, 
                   60000, 
                   10, 
                   WalkMode.WithinSubtree, 
                   null, 
                   null);

TRAP 操作

通常是 SNMP 代理发送 TRAP 消息。以下代码展示了如何从 192.168.1.2 向位于 192.168.1.3 的 SNMP 管理器发送一个空的 SNMP v1 TRAP 消息,

Messenger.SendTrapV1(new IPEndPoint(IPAddress.Parse("192.168.1.3"), 162), 
                     IPAddress.Parse("192.168.1.2"), 
                     new OctetString("public"), 
                     new ObjectIdentifier("1.3.6.1.2.1.1"), 
                     GenericCode.ColdStart, 
                     0, 
                     0, 
                     new List<Variable>();

SNMP v2 及以上版本引入了简化的 TRAP v2 消息,

Messenger.SendTrapV2(0, 
                     VersionCode.V2, 
                     new IPEndPoint(IPAddress.Parse("192.168.1.3"), 162), 
                     new OctetString("public"), 
                     new ObjectIdentifier("1.3.6.1.2.1.1"), 
                     0, 
                     new List<Variable>());

INFORM 操作

通常是 SNMP 代理发送 INFORM 消息。以下代码展示了如何向位于 192.168.1.3 的 SNMP 管理器发送一个空的 INFORM 消息,

Messenger.SendInform(0, 
                     VersionCode.V2, 
                     new IPEndPoint(IPAddress.Parse("192.168.1.3"), 162), 
                     new OctetString("public"), 
                     new ObjectIdentifier("1.3.6.1.2.1.1"), 
                     0, 
                     new List<Variable>(), 
                     2000, 
                     null, 
                     null);

管理器应向此 INFORM 消息发送回复,否则会发生 TimeoutException

为了帮助您理解如何使用 #SNMP 库提供的 API,您可以在 源代码包的 Samples 文件夹中找到更多示例项目。C# 和 VB.NET 示例均可用。

关注点

上述示例应能让您初步了解使用 #SNMP API 执行常见 SNMP 操作的简便性。

我计划撰写更多关于高级用法的文章,例如编译 MIB 文档、SNMP v3 操作以及大型示例,如 #SNMP Compiler/Browser/Agent。

历史

2013 年 6 月 9 日:二进制文件已升级到 8.0 版本。

2012 年 10 月 3 日:添加了更多操作和示例代码。

2012 年 10 月 2 日:修订了开源许可描述。

2012 年 9 月 30 日:本文首次发布。

© . All rights reserved.