java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java的snmp协议获取信息

java通过snmp协议获取物理设备信息

作者:北漂IT民工_程序员_ZG

这篇文章主要介绍了java通过snmp协议获取物理设备信息,snmp中文含义是简单网络管理协议,可用完成对计算机、路由器和其他网络设备的远程管理和监视,本文我们是通过java程序来获取,需要的朋友可以参考下

一、SNMP简介

1、什么是snmp

snmp中文含义是简单网络管理协议,可用完成对计算机、路由器和其他网络设备的远程管理和监视。利用 SNMP 协议可以更好地管理和监控网络。管理工作站可以远程管理所有支持该协议的网络设备,如监视网络状态、修改网络设备配置、接收网络事件警告等。

通俗的讲: 我们可用通过snmp协议获取物理机、存储服务器、交换机等设备的信息,本文我们是通过java程序来获取。

二、SNMP获取信息步骤

1、开启SNMP

首先,我们需要在对应的设备上开启snmp协议,不同的设备可自行百度开启的方法。一般设备有对应的管理软件,可从管理软件开启snmp。

开启snmp需要注意两个地方:

1、开启时会让你设置团体名,一般填pulic就行。

2、端口默认162。

2、MIB文件

举例说明,获取任何一类设备信息,都需要该类设备对应的MIB文件,从MIB文件中解析出OID,每个OID对应一个指标。使用cpu核数对应的OID才能获取核数的个数。

注意:mib文件获取方式

1、打设备厂商客服电话获取。

2、去githup下载: mib链接,下载后不确定哪个MIB文件是我们需要的,只能用mib浏览器自己试呗。

3、MIB浏览器

mib浏览器就相当于一个客户端,用来解析mib文件,可以使用该浏览器模拟snmp请求获取对应的指标信息。

我是用浏览器先测试请求可不可用,然后在从浏览器上拿到oid用java程序获取。

在这里插入图片描述

三、java获取SNMP信息

1、引入maven

    <dependency>
          <groupId>org.snmp4j</groupId>
          <artifactId>snmp4j</artifactId>
          <version>2.8.3</version>
      </dependency>

2、代码实现

注:代码种有snmpGet、snmpWalk两个方法可用获取snmp信息。

snmpGet:是传入的哪个OID的值,就获取该OID的值。

snmpWalk:获取OID的子OID的值。举例说明,传入的OID是1.2.3.4。 获取的是1.2.3.4.1,1.2.3.4.2,1.2.3.4.3的OID值。

import lombok.extern.slf4j.Slf4j;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;
import java.io.IOException;
import java.util.*;
@Slf4j
public class SnmpUtil2 {
    private static Snmp snmp = null;
    private static CommunityTarget target = null;
    private static Integer port = 162;
    private static String ip = "10.11.83.10";
    private static String communityName = "public";
    public static void main(String[] args) throws Exception {
        new SnmpUtil2(ip, port);
        List<TableEvent> tableEvents = snmpWalk("1.3.6.1.4.1.2011.2.235.1.1.15.50.1.12");
        for (TableEvent tableEvent : tableEvents) {
            VariableBinding[] vb = tableEvent.getColumns();
            if (null == vb) {
                continue;
            }
            System.out.println(vb[0].getOid()+"======"+vb[0].getVariable());
        }
        log.info("=================美丽的分割线===================");
        ResponseEvent responseEvent = snmpGet("1.3.6.1.4.1.2011.2.235.1.1.15.50.1.12");
        PDU response = responseEvent.getResponse();
        for (int i = 0; i < response.size(); i++) {
            VariableBinding vb1 = response.get(i);
            System.out.println(vb1.getOid().toString() + "===" + vb1.getVariable());
        }
    }
    public SnmpUtil2(String intranetDeviceIp, Integer snmpPort) throws IOException {
        if (snmp == null) {
            snmp = new Snmp(new DefaultUdpTransportMapping());
            snmp.listen();
        }
        //初始化CommunityTarget
        target = new CommunityTarget();
        target.setCommunity(new OctetString(communityName));
        target.setVersion(SnmpConstants.version2c);
        target.setAddress(new UdpAddress(intranetDeviceIp + "/" + snmpPort));
        target.setTimeout(1000);
        target.setRetries(3);
    }
    private static ResponseEvent snmpGet(String oid) {
        PDU pdu = new PDU();
        pdu.addOID(new VariableBinding(new OID(oid)));
        ResponseEvent re = null;
        try {
            re = snmp.get(pdu, target);
        } catch (Exception e) {
            log.error("snmpGet 异常" + e.getMessage());
        }
        return re;
    }
    private static List<TableEvent> snmpWalk(String oid) {
        TableUtils utils = new TableUtils(snmp, new DefaultPDUFactory(PDU.GETBULK));
        OID[] columnOid = new OID[]{new OID(oid)};
        return utils.getTable(target, columnOid, null, null);
    }
}

3、常用OID

用枚举的方式列了一些常用的OID,包括获取戴尔华为物理机CPU、内存容量及使用率,戴尔存储集群,FS8600,SCV3000,PS6210的容量及使用率 具体看下代码注释

public enum OidEnum {
    //物理机CPU总核数、使用率
    HostCpuUtilization("1.3.6.1.2.1.25.3.3.1.2","物理机CPU总核数和使用率","walk"),
    //物理机内存总量
    HostMemoryTotal("1.3.6.1.2.1.25.2.2.0","物理机内存总量","get"),
    //物理机内存总量(用来计算内存的使用率或者拿到硬盘总量)
    HostMemoryTotalCalUtil("1.3.6.1.2.1.25.2.3.1.5","物理机内存总量(用来计算内存的使用率或者拿到硬盘总量)","walk"),
    //物理机内存使用率(用来计算内存的使用率或者拿到硬盘使用量)
    HostMemoryUsedCalUtil("1.3.6.1.2.1.25.2.3.1.6","物理机内存使用率(用来计算内存的使用率或者拿到硬盘使用量)","walk"),
    /**
     * 华为物理机CPU总核数
     */
    HuaWeiHostCpuTotal("1.3.6.1.4.1.2011.2.235.1.1.15.50.1.12","华为物理机CPU总核数","walk"),
    /**
     * 华为物理机CPU使用率, 单位%
     */
    HuaWeiHostCpuUtilization("1.3.6.1.4.1.2011.2.235.1.1.1.23.0","华为物理机CPU使用率","get"),
    /**
     * 华为物理机内存总量
     */
    HuaWeiHostMemoryTotal("1.3.6.1.4.1.2011.2.235.1.1.16.50.1.4","华为物理机内存总量","walk"),
    /**
     * 华为物理机内存使用率, 单位%
     */
    HuaWeiHostMemoryUtilization("1.3.6.1.4.1.2011.2.235.1.1.1.25.0","华为物理机内存总量","get"),
    //scv3000获得存储总量
    StorageScv3000Total("1.3.6.1.4.1.674.11000.2000.500.1.2.32.1.3", "scv3000获得存储总量(单位GB)","walk"),
    StorageScv3000Alloc("1.3.6.1.4.1.674.11000.2000.500.1.2.32.1.7", "scv3000获得存储分配量(单位GB)","walk"),
    StorageScv3000Used("1.3.6.1.4.1.674.11000.2000.500.1.2.32.1.6", "scv3000获得存储使用量(单位GB)","walk"),
    //PS6210存储总量
    StoragePs6210Total("1.3.6.1.4.1.12740.1.1.2.1.1.1","PS6210存储总量(单位MB)","get"),
    //PS6210存储空闲量
    StoragePs6210Free("1.3.6.1.4.1.12740.1.1.2.1.15.1","PS6210存储空闲量(单位MB)","get"),
    //PS6210存储使用量
    StoragePs6210Used("1.3.6.1.4.1.12740.1.1.2.1.2.1","PS6210存储已使用(单位MB)","get"),
    //FS8600获得存储总量
    StorageFs8600Total("1.3.6.1.4.1.674.11000.2000.200.1.38.1","FS8600获得存储总量(单位MB)","get"),
    //FS8600获得存储使用量
    StorageFs8600Used("1.3.6.1.4.1.674.11000.2000.200.1.38.3","FS8600获得存储使用量(单位MB)","get"),
    //存储总量
    StorageClusterTotal("1.3.6.1.4.1.12124.1.3.1.0", "存储总量(从磁盘集群获取)","get"),
    //存储已使用量
    StorageClusterUsed("1.3.6.1.4.1.12124.1.3.2.0", "存储使用量(从磁盘集群获取)","get");
    private String oid;
    private String describe;
    private String type;
    OidEnum(String oid, String describe, String type) {
        this.oid = oid;
        this.describe = describe;
        this.type = type;
    }
    public String getOid() {
        return oid;
    }
    public String getdDscribe() {
        return describe;
    }
}

四、SNMPTRAP

SNMP Trap是SNMP的一部分,当被监控段出现特定事件,可能是性能问题,甚至是网络设备接口宕掉等,代理端会给管理站发告警事件。通过告警事件,管理站可以通过定义好的方法来处理告警。 trap是主动把告警信息推送到一个监听了162端口的接收程序,接收程序接收到的告警是一个OID,我们需要对oid进行翻译成可读的告警信息,通过该OID去mib文件找到具体告警的详情描述。 比较难的是解析MIB文件,我写了个程序解析mib文件,发现有些文件解析不成功,也不知道为啥,去外网查了下,说是需要引入其他依赖的mib文件,不过我试了很多次还是不行。

1、接收程序代码

import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.CommunityTarget;
import org.snmp4j.MessageDispatcher;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.MessageException;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.log.LogFactory;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.StateReference;
import org.snmp4j.mp.StatusInformation;
import org.snmp4j.security.Priv3DES;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.smi.*;
import org.snmp4j.tools.console.SnmpRequest;
import org.snmp4j.transport.AbstractTransportMapping;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
@Slf4j
public class TrapReceiver implements CommandResponder {
    public TrapReceiver() {
    }
    public static void main(String[] args) {
        TrapReceiver snmp4jTrapReceiver = new TrapReceiver();
        try {
            snmp4jTrapReceiver.listen(new UdpAddress("10.11.26.219/162"));
        } catch (IOException e) {
            System.err.println("Error in Listening for Trap");
            System.err.println("Exception Message = " + e.getMessage());
        }
    }
    /**
     * This method will listen for traps and response pdu's from SNMP agent.
     */
    public synchronized void listen(TransportIpAddress address) throws IOException {
        AbstractTransportMapping transport;
        if (address instanceof TcpAddress) {
            transport = new DefaultTcpTransportMapping((TcpAddress) address);
        } else {
            transport = new DefaultUdpTransportMapping((UdpAddress) address);
        }
        ThreadPool threadPool = ThreadPool.create("DispatcherPool", 10);
        MessageDispatcher mtDispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
        // add message processing models
        mtDispatcher.addMessageProcessingModel(new MPv1());
        mtDispatcher.addMessageProcessingModel(new MPv2c());
        // add all security protocols
        SecurityProtocols.getInstance().addDefaultProtocols();
        SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES());
        // Create Target
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString("1q2w#E$R5t"));
        Snmp snmp = new Snmp(mtDispatcher, transport);
        snmp.addCommandResponder(this);
        transport.listen();
        System.out.println("Listening on " + address);
        try {
            this.wait();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
    /**
     * This method will be called whenever a pdu is received on the given port
     * specified in the listen() method
     */
    public synchronized void processPdu(CommandResponderEvent cmdRespEvent) {
        log.debug("Received PDU...");
        PDU pdu = cmdRespEvent.getPDU();
        System.out.println(cmdRespEvent.toString());
        System.out.println("接收到的trap信息:[发送来源="+cmdRespEvent.getPeerAddress()+",snmp版本="+"2"+",团体名="+"public"+", 携带的变量="+cmdRespEvent.getPDU().getVariableBindings()+"]");
        if (pdu != null) {
            for (int i = 0; i < pdu.size(); i++) {
                VariableBinding vb1 = pdu.get(i);
//                System.err.println(vb1.toString());
            }
            int pduType = pdu.getType();
            if ((pduType != PDU.TRAP) && (pduType != PDU.V1TRAP) && (pduType != PDU.REPORT)
                    && (pduType != PDU.RESPONSE)) {
                pdu.setErrorIndex(0);
                pdu.setErrorStatus(0);
                pdu.setType(PDU.RESPONSE);
                StatusInformation statusInformation = new StatusInformation();
                StateReference ref = cmdRespEvent.getStateReference();
                try {
                    cmdRespEvent.getMessageDispatcher().returnResponsePdu(cmdRespEvent.getMessageProcessingModel(),
                            cmdRespEvent.getSecurityModel(), cmdRespEvent.getSecurityName(),
                            cmdRespEvent.getSecurityLevel(),
                            pdu, cmdRespEvent.getMaxSizeResponsePDU(), ref, statusInformation);
                } catch (MessageException ex) {
                    System.err.println("Error while sending response: " + ex.getMessage());
                    LogFactory.getLogger(SnmpRequest.class).error(ex);
                }
            }
        }
    }
}

2、解析mib文件说明

引入java的两个jar包,mibble-2.9.3.jar和mibble-mibs-2.9.3.jar,我解析时,遇到有的文件解析成功,有的解析报错。没有解析成功的,可用用笨方法,就是用mib浏览器查看oid,把所有的告警OID做成一个字典。 因没有实现成功,具体解析代码我就不贴了。

到此这篇关于java通过snmp协议获取物理设备信息的文章就介绍到这了,更多相关java的snmp协议获取信息内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

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