Snmp JavaAPI
本文只对snmp做简单介绍,主要内容为如何使用及易错点提示,,文章最后贴代码。
1.简单介绍
SNMP:“简单网络管理协议”,用于网络管理的协议。SNMP用于网络设备的管理。SNMP的工作方式:管理员需要向设备获取数据,所以SNMP提供了get操作;管理员需要向设备执行设置操作,所以SNMP提供了set操作;设备需要在重要状况改变的时候,向管理员通报事件的发生,所以SNMP提供了Trap操作。
1.1 Snmp相关概念介绍
1)操作命令
SNMP协议之所以易于使用,这是因为它对外提供了三种用于控制MIB对象的基本操作命令。它们是:Get、Set 和 Trap。
Get:管理站读取代理者处对象的值。它是SNMP协议中使用率最高的一个命令,因为该命令是从网络设备中获得管理信息的基本方式。
Set:管理站设置代理者处对象的值
Trap: 代理者主动向管理站通报重要事件。Trap 消息可以用来通知管理站线路的故障、连接的终端和恢复、认证失败等消息。管理站可相应的作出处理。使用指南
2)SNMP的消息构成
一条snmp消息由版本识别符、团体名、PDU组成:
1. 版本识别符:用于说明现在使用的是哪个版本的SNMP协议,确保SNMP代理使用相同的协议,每个SNMP代理都直接抛弃与自己协议版本不同的数据报。
2. 团体名:团体是基本的安全机制,用于实现SNMP网络管理员访问SNMP管理代理时的身份验证。类似于密码,默认值为 public。
3. 协议数据单元(PDU):PDU (协议数据单元)是SNMP消息中的数据区, 即Snmp通信时报文数据的载体。PDU指明了SNMP的消息类型及其相关参数
3)MIB与OID
1.MIB(管理信息库)
管理信息(MIB)库可以理解成为agent维护的管理对象数据库, MIB数据对象以一种树状分层结构进行组织,这个树状结构中的每个分枝都有一个专用的名字和一个数字形式的标识符。使用这个树状分层结构,MIB浏览器能够以一种方便而且简洁的方式访问整个MIB数据库。可以通过其数字标识符来查找MIB中的数据对象,这个数字标识符号从结构树的顶部(或根部)开始,直到各个叶 子节点(即数据对象)为止。
每一个节点都有一个对象标识符(OID)来唯一的标识,每个节点用数字和字符两种方式显示,其中对象标识符OID是由句点隔开的一组整数,也就是从根节点 通向它的路径。一个带标号节点可以拥有包含其它带标号节点为它的子树,如果没有子树它就是叶子节点,它包含一个值并被称为对象。比如网络设备名的oid 是.1.3.6.1.2.1.1.5.0,其值为设备名称的字符串。
2.OID(Object Identifier)
每个管理对象都有自己的OID(Object Identifier),管理对象通过树状结构进行组织,OID由树上的一系列整数组成,整数之间用点( . )分隔开,树的叶子节点才是真正能够被管理的对象。
1.2 主要代码分析
这该模块对snmp的get、walk、trap三种方式的业务处理进行介绍。
执行过程概述
驻留在被管设备上的AGENT从UDP端口161接受来自网管站的串行化报文,经解码、团体名验证、分析得到管理变量在MIB树中对应的节点,从相应的模块中得到管理变量的值,再形成响应报文,编码发送回网管站。网管站得到响应报文后,再经同样的处理,最终显示结果。下面根据RFC1157详细介绍Agent接受到报文后采取的动作:首先解码生成用内部数据结构表示的报文,解码依据ASN.1的基本编码规则,如果在此过程中出现错误导致解码失败则丢弃该报文,不做进一步处理。第二步:将报文中的版本号取出,如果与本Agent支持的SNMP版本不一致,则丢弃该报文,不做进一步处理。当前北研的数据通信产品只支持SNMP版本1。第三步:将报文中的团体名取出,此团体名由发出请求的网管站填写。如与本设备认可的团体名不符,则丢弃该报文,不做进一步处理,同时产生一个陷阱报文。SNMPv1只提供了较弱的安全措施,在版本3中这一功能将大大加强。第四步:从通过验证的ASN.1对象中提出协议数据单元PDU,如果失败,丢弃报文,不做进一不处理。否则处理PDU,结果将产生一个报文,该报文的发送目的地址应同收到报文的源地址一致。根据不同的PDU,SNMP协议实体将做不同的处理
1.3 环境准备
在项目中添加maven jar包依赖,如下图所示。
1.4 代码实现
1.4.1 Trap和get方式获取信息
-
初始化snmp,并开启监听
-
初始化get和walk方式请求的目标对象信息
-
根据oid创建请求的报文
-
对返回的消息体进行处理
Get方式:
Walk方式:
5. 初始化、创建目标对象、创建报文与get方式一致,此处住在赘述
1.4.2 Trap方式
初始化与get方式一致,此处不在赘述
1.Trap消息处理方法,此方法会接收trap推送的信息
2 常见问题
1.使用get方式请求获取信息,一直返回 noSuchObject说明没有找到该节点,需要确定该oid是否正确。若没有返回说明连接不正常,需要检查各个版本、用户名、密码、协议、团体名等配置信息是否正确。
2. 创建目标对象时,使用v1、v2版本时需要指定团体名,使用v3需要指定安全名。
3.配置v3用户时,最好通过管理口进行配置,web页面配置可能不生效。
3.主要代码demo
3.1get方式
package com.snmp.collection.get_collection.collectionforII;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.*;
/**
* @description: get方式获取数据
* @author: yghhz
* @create: 2020-11-15 10:14
**/
public class MultiThreadedGetDemo {
private static final Logger LOGGER = LogManager.getLogger(MultiThreadedGetDemo.class);
//用户名
private String username = "nms2-admin";
//鉴权密码
private String authPassword = "hello123";
//数据加密密码
private String privPassword = "hello123";
//trap地址
private String address = "udp:192.160.0.1/162";
//get 地址
private String addressGet = "udp:192.160.0.2/161";
private MultiThreadedMessageDispatcher dispatcher;
private Snmp snmp = null;
private Address listenAddress;
private ThreadPool threadPool;
public MultiThreadedGetDemo() {
}
public void initSnmp() throws IOException {
//1、初始化多线程消息转发类
MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
//其中要增加三种处理模型。如果snmp初始化使用的是Snmp(TransportMapping<? extends Address> transportMapping) ,就不需要增加
messageDispatcher.addMessageProcessingModel(new MPv1());
messageDispatcher.addMessageProcessingModel(new MPv2c());
//当要支持snmpV3版本时,需要配置user
OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
OctetString userName1 = new OctetString(username);
OctetString authPass = new OctetString(authPassword);
OctetString privPass = new OctetString(privPassword);
UsmUser user = new UsmUser(userName1, AuthMD5.ID, authPass, PrivAES128.ID, privPass);
usm.addUser(user.getSecurityName(), user);
messageDispatcher.addMessageProcessingModel(new MPv3(usm));
//2、创建transportMapping ip为本地ip,可以不设置
TransportMapping<?> transportMapping = new DefaultUdpTransportMapping();
//3、正式创建snmp
snmp = new Snmp(messageDispatcher, transportMapping);
//开启监听
snmp.listen();
}
private Target createTarget(String oid) {
Target target = null;
int version = 1;
if (!(version == SnmpConstants.version3 || version == SnmpConstants.version2c || version == SnmpConstants.version1)) {
//log.error("参数version异常");
return target;
}
if (version == SnmpConstants.version3) {
target = new UserTarget();
//snmpV3需要设置安全级别和安全名称,其中安全名称是创建snmp指定user设置的new OctetString("SNMPV3")
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setSecurityName(new OctetString(this.use