使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。
引言
SNMP(简单网络管理协议)是一种用于网络设备管理的标准协议。本文将介绍如何使用 Java 和 SNMP4J(一个开源的 SNMP 实现库)进行 SNMP 操作。我们将通过编写 SnmpUtil 类来演示如何进行 SNMP 初始化、创建 PDU、发送 SNMP 请求并处理响应。
环境准备
首先,确保您已经添加了 SNMP4J 依赖。可以通过 Maven 或 Gradle 进行依赖管理。
org.snmp4j
snmp4j
2.8.6
implementation 'org.snmp4j:snmp4j:2.8.6'
SnmpUtil 类概述
以下是编写 SnmpUtil 类的整体结构。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。
类的静态初始化
我们在这使用静态块来初始化 SNMP 对象,确保整个应用程序生命周期中只进行一次初始化。
public class SnmpUtil {
private static final Logger log = LoggerFactory.getLogger(SnmpUtil.class);
private static Snmp snmp = null;
static {
try {
initSnmp();
} catch (IOException e) {
log.error("SNMP 初始化失败", e);
}
}
private static synchronized void initSnmp() throws IOException {
if (snmp == null) {
MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
messageDispatcher.addMessageProcessingModel(new MPv1());
messageDispatcher.addMessageProcessingModel(new MPv2c());
OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"),
PrivAES128.ID, new OctetString("privPassword"));
usm.addUser(user.getSecurityName(), user);
messageDispatcher.addMessageProcessingModel(new MPv3(usm));
TransportMapping transportMapping = new DefaultUdpTransportMapping();
snmp = new Snmp(messageDispatcher, transportMapping);
snmp.listen();
}
}
}
创建目标
编写createTarget 方法用于创建 SNMP 目标,支持 SNMP v1, v2c 和 v3 版本。
private static Target createTarget(int version, String community, String ipAddress, int port) {
Target target = null;
if (!(version == SnmpConstants.version3 || version == SnmpConstants.version2c || version == SnmpConstants.version1)) {
log.error("参数version异常");
return target;
}
if (version == SnmpConstants.version3) {
target = new UserTarget();
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setSecurityName(new OctetString("SNMPV3"));
} else {
target = new CommunityTarget();
((CommunityTarget) target).setCommunity(new OctetString(community));
if (version == SnmpConstants.version2c) {
target.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
}
}
target.setVersion(version);
target.setAddress(GenericAddress.parse("udp:" + ipAddress + "/" + port));
target.setRetries(5);
target.setTimeout(3000);
return target;
}
创建 PDU
编写createPDU 方法用于创建 Protocol Data Unit (PDU),这是 SNMP 消息的基本构成单元。
private static PDU createPDU(int version, int type, String oid) {
PDU pdu = null;
if (version == SnmpConstants.version3) {
pdu = new ScopedPDU();
} else {
pdu = new PDUv1();
}
pdu.setType(type);
pdu.add(new VariableBinding(new OID(oid)));
return pdu;
}
private static PDU createPDU(int version, int type, List oids) {
PDU pdu = null;
if (version == SnmpConstants.version3) {
pdu = new ScopedPDU();
} else {
pdu = new PDU();
}
pdu.setType(type);
for (String oid : oids) {
pdu.add(new VariableBinding(new OID(oid)));
}
return pdu;
}
发送 SNMP 请求
编写snmpWalk 方法用于发送 GETNEXT 请求,并处理响应。此处注意,不一定都是用GETNEXT请求,也可以用GET请求,两者区别故名思义,一个是获取下一条oid,一个是获取自己本身
public static PDU snmpWalk(String ipAddr, int port, int version, String community, String oid) {
try {
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = createPDU(version, PDU.GETNEXT, oid);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
return response;
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
return new PDU();
}
}
public static PDU snmpWalk(String ipAddr, int port, int version, String community, List oids) {
try {
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = createPDU(version, PDU.GETNEXT, oids);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
return response;
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
return new PDU();
}
}
处理 SNMP 响应
编写snmpWalkAll 和 snmpWalkSegment 方法用于处理连续的 SNMP 响应,直到到达 MIB 的末尾。
public static List snmpWalkAll(String ipAddr, int port, int version, String community, String startOid) {
List results = new ArrayList();
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(startOid)));
while (true) {
try {
pdu.setType(PDU.GETNEXT);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
if (response != null & response.size() > 0 && response.getErrorStatus() == 0) {
if (response.get(0).getVariable().toString().equals("endOfMibView")) {
break;
}
results.addAll(response.getVariableBindings());
pdu.setRequestID(null); // Reset request ID for the next request
pdu.remove(0); // Remove the old request
pdu.add(response.get(0)); // Add the new request based on the last response
} else {
break;
}
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
break;
}
}
return results;
}
// ...其他代码见完整代码
完整代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SnmpUtil {
private static final Logger log = LoggerFactory.getLogger(SnmpUtil.class);
private static Snmp snmp = null; // 将共享资源的访问控制为静态初始化
static {
// 将 SNMP 对象的初始化放在静态块中,确保只初始化一次
try {
initSnmp();
} catch (IOException e) {
log.error("SNMP 初始化失败", e); // 记录初始化失败的异常信息
}
}
private static synchronized void initSnmp() throws IOException { // 添加 synchronized 关键字保证线程安全
if (snmp == null) {
MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
messageDispatcher.addMessageProcessingModel(new MPv1());
messageDispatcher.addMessageProcessingModel(new MPv2c());
OctetString localEngineID = new OctetString(MPv3.createLocalEngineID());
USM usm = new USM(SecurityProtocols.getInstance().addDefaultProtocols(), localEngineID, 0);
UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"),
PrivAES128.ID, new OctetString("privPassword"));
usm.addUser(user.getSecurityName(), user);
messageDispatcher.addMessageProcessingModel(new MPv3(usm));
TransportMapping transportMapping = new DefaultUdpTransportMapping();
snmp = new Snmp(messageDispatcher, transportMapping);
snmp.listen();
}
}
private static Target createTarget(int version, String community, String ipAddress, int port) {
Target target = null;
if (!(version == SnmpConstants.version3 || version == SnmpConstants.version2c || version == SnmpConstants.version1)) {
log.error("参数version异常"); // 保持错误日志记录
return target;
}
if (version == SnmpConstants.version3) {
target = new UserTarget();
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setSecurityName(new OctetString("SNMPV3"));
} else {
target = new CommunityTarget();
((CommunityTarget) target).setCommunity(new OctetString(community));
if (version == SnmpConstants.version2c) {
target.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c);
}
}
target.setVersion(version);
target.setAddress(GenericAddress.parse("udp:" + ipAddress + "/" + port));
target.setRetries(5);
target.setTimeout(3000);
return target;
}
/**
* 创建 PDU 对象
* @param version
* @param type
* @param oid
* @return
*/
private static PDU createPDU(int version, int type, String oid) {
PDU pdu = null;
if (version == SnmpConstants.version3) {
pdu = new ScopedPDU();
} else {
pdu = new PDUv1();
}
pdu.setType(type);
pdu.add(new VariableBinding(new OID(oid)));
return pdu;
}
/**
* 创建 PDU 对象
* @param version
* @param type
* @param oids
* @return
*/
private static PDU createPDU(int version, int type, List oids) {
PDU pdu = null;
if (version == SnmpConstants.version3) {
pdu = new ScopedPDU();
} else {
pdu = new PDU();
}
pdu.setType(type);
for (String oid : oids) {
pdu.add(new VariableBinding(new OID(oid)));
}
return pdu;
}
/**
* 获取 SNMP 响应
* @param ipAddr
* @param port
* @param version
* @param community
* @param oid
* @return
*/
public static PDU snmpWalk(String ipAddr, int port, int version, String community, String oid) {
try {
// 由于 snmp 对象已在静态块中初始化,这里不再需要调用 initSnmp
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = createPDU(version, PDU.GETNEXT, oid); // 保持内部字符串不变
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
return response;
} catch (IOException e) {
log.error("SNMP 发送请求失败", e); // 增加异常日志记录
return new PDU(); // 在异常情况下仍然返回一个新的 PDU 对象,但已记录错误信息
}
}
/**
* 获取 SNMP 响应
* @param ipAddr
* @param port
* @param version
* @param community
* @param oids
* @return
*/
public static PDU snmpWalk(String ipAddr, int port, int version, String community, List oids) {
try {
// 由于 snmp 对象已在静态块中初始化,这里不再需要调用 initSnmp
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = createPDU(version, PDU.GETNEXT, oids); // 保持内部字符串不变
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
return response;
} catch (IOException e) {
log.error("SNMP 发送请求失败", e); // 增加异常日志记录
return new PDU(); // 在异常情况下仍然返回一个新的 PDU 对象,但已记录错误信息
}
}
/**
* 获取 SNMP 响应
* @param ipAddr
* @param port
* @param version
* @param community
* @param startOid
* @return
*/
public static List snmpWalkAll(String ipAddr, int port, int version, String community, String startOid) {
List results = new ArrayList();
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(startOid)));
while (true) {
try {
pdu.setType(PDU.GETNEXT);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
if (response != null & response.size() > 0 && response.getErrorStatus() == 0) {
if (response.get(0).getVariable().toString().equals("endOfMibView")) {
break;
}
results.addAll(response.getVariableBindings());
pdu.setRequestID(null); // Reset request ID for the next request
pdu.remove(0); // Remove the old request
pdu.add(response.get(0)); // Add the new request based on the last response
} else {
break;
}
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
break;
}
}
return results;
}
/**
* 获取 SNMP 响应
* @param ipAddr
* @param port
* @param version
* @param community
* @param startOid
* @return
*/
public static List snmpWalkSegment(String ipAddr, int port, int version, String community, String startOid) {
List results = new ArrayList();
Target target = createTarget(version, community, ipAddr, port);
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(startOid)));
while (true) {
try {
pdu.setType(PDU.GETNEXT);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
if (response != null & response.size() > 0 && response.getErrorStatus() == 0) {
VariableBinding vb = response.get(0);
results.add(vb);
// Check if we have reached the end of the branch
if (!vb.getOid().startsWith(new OID(startOid)) || vb.getVariable().toString().equals("endOfMibView")) {
break;
}
pdu.setRequestID(null); // Reset request ID for the next request
pdu.remove(0); // Remove the old request
pdu.add(vb); // Add the new request based on the last response
System.out.println("OID: " + vb.getOid() + ", Value: " + vb.getVariable());
} else {
break;
}
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
break;
}
}
return results;
}
public static List snmpWalkSegment(String ipAddr, int port, int version, String community, List startOids) {
List results = new ArrayList();
Target target = createTarget(version, community, ipAddr, port);
for(String startOid: startOids){
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID(startOid)));
while (true) {
try {
pdu.setType(PDU.GETNEXT);
ResponseEvent responseEvent = snmp.send(pdu, target);
PDU response = responseEvent.getResponse();
if (response != null & response.size() > 0 && response.getErrorStatus() == 0) {
VariableBinding vb = response.get(0);
results.add(vb);
// Check if we have reached the end of the branch
if (!vb.getOid().startsWith(new OID(startOid)) || vb.getVariable().toString().equals("endOfMibView")) {
break;
}
pdu.setRequestID(null); // Reset request ID for the next request
pdu.remove(0); // Remove the old request
pdu.add(vb); // Add the new request based on the last response
System.out.println("OID: " + vb.getOid() + ", Value: " + vb.getVariable());
} else {
break;
}
} catch (IOException e) {
log.error("SNMP 发送请求失败", e);
break;
}
}
}
return results;
}
public static void main(String[] args) {
PDU response = SnmpUtil.snmpWalk("127.0.0.1", 161, SnmpConstants.version2c, "public", ".1");
if (response != null & response.getErrorStatus() == 0) {
for (VariableBinding vb : response.getVariableBindings()) {
System.out.println("OID: " + vb.getOid() + ", Value: " + vb.getVariable());
}
} else {
System.out.println("Error in response: " + response.getErrorStatusText());
}
}
}
总结
通过本文的讲解,您应该已经掌握了如何使用 Java 和 SNMP4J 库进行 SNMP 操作。我们介绍了 SnmpUtil 类的设计和实现,包括 SNMP 初始化、创建目标、创建 PDU、发送 SNMP 请求和处理响应等内容。希望这篇教程能够帮助您更好地理解和使用 SNMP4J 进行网络设备管理
使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。使用Java和SNMP4J实现SNMP操作 以下编写 SnmpUtil 类的教程。该类提供了静态方法来初始化 SNMP、创建 SNMP 目标、创建 PDU、发送 SNMP 请求和处理响应。