java 通过snmp协议获取物理机CPU、内存容量及使用率,存储的容量及使用率

java 用snmp协议获取物理机CPU、内存容量及使用率,存储的容量及使用率,java获取trap告警

  • 一、SNMP简介
    • 1、什么是snmp
  • 二、SNMP获取信息步骤
    • 1、开启SNMP
    • 2、MIB文件
    • 3、MIB浏览器
  • 三、java获取SNMP信息
    • 1、引入maven
    • 2、代码实现
    • 3、常用OID
  • 四、SNMPTRAP
    • 1、接收程序代码
    • 2、解析mib文件说明

一、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程序获取。

点击进入mib浏览器下载地址

java 通过snmp协议获取物理机CPU、内存容量及使用率,存储的容量及使用率_第1张图片

三、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做成一个字典。
因没有实现成功,具体解析代码我就不贴了。

如果我有哪个地方写的不合适的地方,或者需要交流的可用加我qq:739749855

你可能感兴趣的:(自创,java,网络,服务器)