java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java和SNMP4J实现SNMP

使用Java和SNMP4J实现SNMP操作完整代码

作者:bigxiamu

这篇文章主要介绍了如何使用Java和SNMP4J库进行SNMP操作,包括初始化SNMP、创建目标、创建PDU、发送SNMP请求和处理响应等内容,通过编写SnmpUtil类,展示了完整的SNMP操作流程,需要的朋友可以参考下

引言

SNMP(简单网络管理协议)是一种用于网络设备管理的标准协议。本文将介绍如何使用 Java 和 SNMP4J(一个开源的 SNMP 实现库)进行 SNMP 操作。我们将通过编写 SnmpUtil 类来演示如何进行 SNMP 初始化、创建 PDU、发送 SNMP 请求并处理响应。

环境准备

首先,确保您已经添加了 SNMP4J 依赖。可以通过 Maven 或 Gradle 进行依赖管理。

<dependency>
    <groupId>org.snmp4j</groupId>
    <artifactId>snmp4j</artifactId>
    <version>2.8.6</version>
</dependency>
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<String> 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<String> 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<VariableBinding> snmpWalkAll(String ipAddr, int port, int version, String community, String startOid) {
    List<VariableBinding> 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<String> 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<String> 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<VariableBinding> snmpWalkAll(String ipAddr, int port, int version, String community, String startOid) {
        List<VariableBinding> 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<VariableBinding> snmpWalkSegment(String ipAddr, int port, int version, String community, String startOid) {
        List<VariableBinding> 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<VariableBinding> snmpWalkSegment(String ipAddr, int port, int version, String community, List<String> startOids) {
        List<VariableBinding> 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操作的文章就介绍到这了,更多相关Java和SNMP4J实现SNMP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文