SNMP协议实践

人机料法环专家
发布于 2022-6-1 21:19
浏览
1收藏

SNMP协议实践

一、背景

物联网时代,软件系统的建设越来越多的需要与设备、设备采集通信协议进行打交道。

工作中,遇到对华为桌面云实现统一监控运维的项目需求。基本功能要求是,通过对华为桌面云FA、FC平台北向接口的数据采集,实现对华为桌面云服务器运行状态的监测,包括CPU使用率、内存、网络、硬盘等使用情况,故障告警的监听处理等内容。技术预研阶段涉及对SNMP协议的预研了解,以下是对SNMP协议内容的一些总结,涉及内容主要如下:

  • Snmp基本概念
  • linux下安装和配置SNMP
  • JAVA开源组件snmp4j

二、Snmp基本概念

2.1 什么是SNMP协议

SNMP是英文"Simple Network Management Protocol"的缩写,简单网络管理协议(SNMP) 是专门设计用于在 IP 网络管理网络节点(服务器、工作站、路由器、交换机、HUBS等)的一种标准协议,它属于TCP/IP五层协议中的应用层协议,用于网络管理的协议。SNMP主要用于网络设备的管理。由于SNMP协议简单可靠 ,受到了众多厂商的欢迎,成为了目前最为广泛的网管协议。

​ SNMP协议由SNMP管理站(manager)和SNMP代理(Agent)两部分构成。SNMP管理站是中心节点,负责收集维护各个SNMP元素的信息,并对这些信息进行处理;SNMP代理运行在各个被管理的网络节点上,负责统计该节点的各项指标信息,并且负责与SNMP管理站交互,接收并执行管理站的命令,上传各种本地的网络信息。
SNMP协议实践-鸿蒙开发者社区

2.2 SNMP组成

一套完整的SNMP系统主要包括管理信息库(MIB)、管理信息结构(SMI)及SNMP报文协议。

  • MIB:任何一个被管理的资源都表示成一个对象,称为被管理的对象。MIB是被管理对象的集合。它定义了被管理对象的一系列属性:对象的名称、对象的访问权限和对象的数据类型等。每个SNMP设备(Agent)都有自己的MIB。MIB也可以看作是NMS和Agent之间的沟通桥梁。

SNMP协议实践-鸿蒙开发者社区

  • SMI:SMI定义了SNMP框架所用信息的组织、组成和标识,它还为描述MIB对象和描述协议怎样交换信息奠定了基础。
  • SNMP报文:SNMP协议定义了数据包的格式,一条SNMP消息由"版本号"、"SNMP共同体名"和"协议数据单元(PDU)"构成,数据包的长度不是固定的。

SNMP协议实践-鸿蒙开发者社区

2.3 SNMP协议工作方式

​ SNMP主要采用UDP协议在manager和agent之间传输信息。 SNMP采用UDP 161端口接收和发送请求,162端口接收trap,执行SNMP的设备缺省都必须采用这些端口。SNMP消息全部通过UDP端口161接收,只有Trap信息采用UDP端口162。

​ 简单讲,SNMP管理站通过UDP协议向SNMP代理发送各种命令,当SNMP代理收到命令后,返回SNMP管理站需要的参数。当SNMP代理检测到网络元素异常的时候,也可以主动向SNMP管理站发送消息,通告当前异常状况。SNMP协议提供了三种用于控制MIB对象的基本操作命令:

  • Get:用于读取代理者处对象的值。它是SNMP协议中使用率最高的一个命令,该命令是从网络设备中获得管理信息的基本方式。
  • Set:manager需要向设备执行设置操作,SNMP提供了Set操作,可以通过它来改动设备的配置或控制设备的运转状态。它可以设置设备的名称、关掉一个端口或清除一个地址解析表中的项等。
  • Trap: agent主动向manager通报重要事件。它的主要用途是在网络管理系统没有明确要求的前提下,由管理代理通知网络管理系统有一些特别的情况或问题 发生了。如果发生意外情况,客户会向服务器的162端口发送一个消息,告知服务器指定的变量值发生了变化。通常由服务器请求而获得的数据由服务器的161 端口接收。Trap 消息可以用来通知管理站线路的故障、连接的终端和恢复、认证失败等消息。管理站可相应的作出处理。

2.4 SNMP 协议版本

​ SNMP协议在1988年被制定,1992年发布了SNMPv2版本,以增强SNMPv1的安全性和功能。目前SNMP协议共有v1,v2,v3三个版本:

  • SNMP v1是SNMP协议的最初版本,不过依然是众多厂家实现SNMP基本方式。
  • SNMP v2通常被指是基于community的SNMP V2。Community实质上就是**。
  • SNMP v3 是最新版本的SNMP。它对网络管理最大的贡献在于其安全性。增加了对认证和密文传输的支持。

三、linux下安装和配置SNMP

3.1安装snmp

# 安装SNMP
yum install -y net-snmp*
# 备份SNMP配置
/etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.bak
# 添加修改配置
vim /etc/snmp/snmpd.conf
rocommunity SZ-SNMP-PRIVATE
group   notConfigGroup v1           notConfigUser
group   notConfigGroup v2c           notConfigUser
# 重启SNMP
service snmpd restart
# 查看主机
snmpwalk -v 2c -c SZ-SNMP-PRIVATE 192.168.1.112

3.2 常用OID

系统参数(1.3.6.1.2.1.1)
OID 描述 备注 请求方式
.1.3.6.1.2.1.1.1.0 获取系统基本信息 SysDesc GET
.1.3.6.1.2.1.1.3.0 监控时间 sysUptime GET
.1.3.6.1.2.1.1.4.0 系统联系人 sysContact GET
.1.3.6.1.2.1.1.5.0 获取机器名 SysName GET
.1.3.6.1.2.1.1.6.0 机器坐在位置 SysLocation GET
.1.3.6.1.2.1.1.7.0 机器提供的服务 SysService GET
.1.3.6.1.2.1.25.4.2.1.2 系统运行的进程列表 hrSWRunName WALK
.1.3.6.1.2.1.25.6.3.1.2 系统安装的软件列表 hrSWInstalledName WALK
网络接口(1.3.6.1.2.1.2)
OID 描述 备注 请求方式
.1.3.6.1.2.1.2.1.0 网络接口的数目 IfNumber GET
.1.3.6.1.2.1.2.2.1.2 网络接口信息描述 IfDescr WALK
.1.3.6.1.2.1.2.2.1.3 网络接口类型 IfType WALK
.1.3.6.1.2.1.2.2.1.4 接口发送和接收的最大IP数据报[BYTE] IfMTU WALK
.1.3.6.1.2.1.2.2.1.5 接口当前带宽[bps] IfSpeed WALK
.1.3.6.1.2.1.2.2.1.6 接口的物理地址 IfPhysAddress WALK
.1.3.6.1.2.1.2.2.1.8 接口当前操作状态[up|down] IfOperStatus WALK
.1.3.6.1.2.1.2.2.1.10 接口收到的字节数 IfInOctet WALK
.1.3.6.1.2.1.2.2.1.16 接口发送的字节数 IfOutOctet WALK
.1.3.6.1.2.1.2.2.1.11 接口收到的数据包个数 IfInUcastPkts WALK
.1.3.6.1.2.1.2.2.1.17 接口发送的数据包个数 IfOutUcastPkts WALK
CPU及负载
OID 描述 备注 请求方式
. 1.3.6.1.4.1.2021.11.9.0 用户CPU百分比 ssCpuUser GET
. 1.3.6.1.4.1.2021.11.10.0 系统CPU百分比 ssCpuSystem GET
. 1.3.6.1.4.1.2021.11.11.0 空闲CPU百分比 ssCpuIdle GET
. 1.3.6.1.4.1.2021.11.50.0 原始用户CPU使用时间 ssCpuRawUser GET
.1.3.6.1.4.1.2021.11.51.0 原始nice占用时间 ssCpuRawNice GET
. 1.3.6.1.4.1.2021.11.52.0 原始系统CPU使用时间 ssCpuRawSystem. GET
. 1.3.6.1.4.1.2021.11.53.0 原始CPU空闲时间 ssCpuRawIdle GET
. 1.3.6.1.2.1.25.3.3.1.2 CPU的当前负载,N个核就有N个负载 hrProcessorLoad WALK
. 1.3.6.1.4.1.2021.11.3.0 ssSwapIn GET
. 1.3.6.1.4.1.2021.11.4.0 SsSwapOut GET
. 1.3.6.1.4.1.2021.11.5.0 ssIOSent GET
. 1.3.6.1.4.1.2021.11.6.0 ssIOReceive GET
. 1.3.6.1.4.1.2021.11.7.0 ssSysInterrupts GET
. 1.3.6.1.4.1.2021.11.8.0 ssSysContext GET
. 1.3.6.1.4.1.2021.11.54.0 ssCpuRawWait GET
. 1.3.6.1.4.1.2021.11.56.0 ssCpuRawInterrupt GET
. 1.3.6.1.4.1.2021.11.57.0 ssIORawSent GET
. 1.3.6.1.4.1.2021.11.58.0 ssIORawReceived GET
. 1.3.6.1.4.1.2021.11.59.0 ssRawInterrupts GET
. 1.3.6.1.4.1.2021.11.60.0 ssRawContexts GET
. 1.3.6.1.4.1.2021.11.61.0 ssCpuRawSoftIRQ GET
. 1.3.6.1.4.1.2021.11.62.0 ssRawSwapIn. GET
. 1.3.6.1.4.1.2021.11.63.0 ssRawSwapOut GET
.1.3.6.1.4.1.2021.10.1.3.1 Load5 GET
.1.3.6.1.4.1.2021.10.1.3.2 Load10 GET
.1.3.6.1.4.1.2021.10.1.3.3 Load15 GET
内存及磁盘(1.3.6.1.2.1.25)
OID 描述 备注 请求方式
.1.3.6.1.2.1.25.2.2.0 获取内存大小 hrMemorySize GET
.1.3.6.1.2.1.25.2.3.1.1 存储设备编号 hrStorageIndex WALK
.1.3.6.1.2.1.25.2.3.1.2 存储设备类型 hrStorageType[OID] WALK
.1.3.6.1.2.1.25.2.3.1.3 存储设备描述 hrStorageDescr WALK
.1.3.6.1.2.1.25.2.3.1.4 簇的大小 hrStorageAllocationUnits WALK
.1.3.6.1.2.1.25.2.3.1.5 簇的的数目 hrStorageSize WALK
.1.3.6.1.2.1.25.2.3.1.6 使用多少,跟总容量相除就是占用率 hrStorageUsed WALK
.1.3.6.1.4.1.2021.4.3.0 Total Swap Size(虚拟内存) memTotalSwap GET
.1.3.6.1.4.1.2021.4.4.0 Available Swap Space memAvailSwap GET
.1.3.6.1.4.1.2021.4.5.0 Total RAM in machine memTotalReal GET
.1.3.6.1.4.1.2021.4.6.0 Total RAM used memAvailReal GET
.1.3.6.1.4.1.2021.4.11.0 Total RAM Free memTotalFree GET
.1.3.6.1.4.1.2021.4.13.0 Total RAM Shared memShared GET
.1.3.6.1.4.1.2021.4.14.0 Total RAM Buffered memBuffer GET
.1.3.6.1.4.1.2021.4.15.0 Total Cached Memory memCached GET
.1.3.6.1.4.1.2021.9.1.2 Path where the disk is mounted dskPath WALK
.1.3.6.1.4.1.2021.9.1.3 Path of the device for the partition dskDevice WALK
.1.3.6.1.4.1.2021.9.1.6 Total size of the disk/partion (kBytes) dskTotal WALK
.1.3.6.1.4.1.2021.9.1.7 Available space on the disk dskAvail WALK
.1.3.6.1.4.1.2021.9.1.8 Used space on the disk dskUsed WALK
.1.3.6.1.4.1.2021.9.1.9 Percentage of space used on disk dskPercent WALK
.1.3.6.1.4.1.2021.9.1.10 Percentage of inodes used on disk dskPercentNode WALK

四、JAVA开源组件snmp4j

4.1 snmp4j简介

SNMP4J是一个用Java来实现SNMP协议的开源项目.它支持以命令行的形式进行管理与响应。SNMP4J是纯面向对象设计与SNMP++(用C++实现SNMPv1/v2c/v3)相类似。

SNMP4J API 提供以下下特性:

  • 支持MD5和SHA验证,DES,3DES,AES128、AES192和AES256加密的SNMPv3。
  • 支持MPv1,MPv2C和MPv3,带执行的可阻塞的信息处理模块。
  • 全部PDU格式。
  • 可阻塞的传输拓扑。支持UPD、TCP、TLS 。
  • 可阻塞的超时模块。
  • 同步和异步请求。
  • 命令发生器以及命令应答器的支持。
  • 基于Apache license的开源免费。
  • JAVA 1.4.1或更高版本(2.0或更高版本需要jdk1.6及以上的支持)。
  • 基于LOG4J记录日志。
  • 使用GETBULK实现Row-based的有效的异步表格获取。
  • 支持多线程。

4.2 snmp4j示例

jar包引入

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

示例代码

package com.wf.example.snmp;

import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

import java.io.IOException;
import java.util.Vector;

/**
 * @author wf
 * @ClassName:SnmpUtil
 * @Description: SNMP协议
 * @date 2021/11/16 14:36
 */
public class SnmpDemo {
    private Snmp snmp = null;
    private Address targetAddress = null;
    //SNMP 代理地址
    private String agentAddress="";
    //SNMP trap上报监听地址
    private String trapAddress="";
    //[身份认证]组织团体名称
    private String agentCommunity="";

    /**
     * ========================
     * 测试SNMP协议
     * 1、get方法获取信息(只演示了同步方式)
     * 2、set方法修改信息
     * 3、trap监听告警上报
     * ========================
     */
    public static void main(String[] args) {
        try {
            //本机(windows 10)测试:GET获取信息【成功】、SET修改信息【成功】
            System.out.println("======本机测试开始======");
            getPDUTest("udp:127.0.0.1/161","public");
            setPDUTest("udp:127.0.0.1/161","public");
            //配合模拟发送程序进行接收:SnmpUtilSendTrap
            SnmpDemo util = new SnmpDemo("udp:127.0.0.1/161","192.168.215.160/162","public");
            util.listen();
            System.out.println("======本机测试结束======");

            //121.37.0.11(linux)服务器测试:GET获取信息【成功】、SET修改信息【成功】 
            System.out.println("======121.37.0.11服务器测试开始======");
            getPDUTest("udp:121.37.0.11/161","SZ-SNMP-PRIVATE");
            //setPDUTest("udp:121.37.0.11/161","SZ-SNMP-PRIVATE");
            System.out.println("======121.37.0.11服务器测试结束======");

            //192.168.21.110 华为云桌面测试服务器:trap报警【成功】、GET获取信息【成功】
            System.out.println("======192.168.22.110服务器测试开始======");
            //getPDUTest("udp:192.168.22.110/161","talkweb");
            SnmpDemo util1 = new SnmpDemo("udp:192.168.22.110/161","192.168.215.160/162","talkweb");
            util1.listen();
            System.out.println("======192.168.22.110服务器测试结束======");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * GET测试,需要预装配置SNMP协议,并进行团体名称,读写权限配置
     * 1、测试通过:读取计算机名称
     */
    public static void getPDUTest(String agentAddress,String agentCommunity)throws IOException{
        //本机测试==测试通过
        SnmpDemo util = new SnmpDemo(agentAddress,agentCommunity);
        // 获取机器名 .1.3.6.1.2.1.1.5.0
        // 获取系统基本信息 .1.3.6.1.2.1.1.1.0
        OID[] oids=new OID[]{new OID(".1.3.6.1.2.1.1.5.0"),new OID(".1.3.6.1.2.1.1.1.0")};
        //获取计算机名称
        util.getPDU(oids);
        //设置计算机名称  DESKTOP-E109030 |
    }
    /**
     * SET测试,需要预装配置SNMP协议,并进行团体名称,读写权限配置
     * 新建团体名称:默认权限是只读,写入权限需要另外分配设置
     * 1、测试通过:改写计算机名称(只能改写到MIB库中,不能反馈到计算机的信息面板)
     */
    public static void setPDUTest(String agentAddress,String agentCommunity)throws IOException{
        //本机测试==测试通过
        SnmpDemo util = new SnmpDemo(agentAddress,agentCommunity);
        // 机器名 .1.3.6.1.2.1.1.5.0
        VariableBinding[] variableBindings=new VariableBinding []{new VariableBinding(new OID(".1.3.6.1.2.1.1.5.0"),new OctetString("ttt"))};
        //获取计算机名称
        util.setPDU(variableBindings);
    }

    public SnmpDemo(String agentAddress, String agentCommunity) throws IOException{
        this.agentAddress=agentAddress;
        this.agentCommunity=agentCommunity;
        this.initComm();
    }
    /**
     * 初始化
     */
    public void initComm() throws IOException {
        // 设置Agent方的IP和端口
        targetAddress = GenericAddress.parse(agentAddress);
        TransportMapping transport = new DefaultUdpTransportMapping();
        snmp = new Snmp(transport);
        transport.listen();
    }
    /**
     * 通过OID获得一个或多个信息
     * @param oids
     */
    public void getPDU(OID [] oids) throws IOException {
        PDU pdu = new PDU();
        for (OID oid:oids){
            pdu.add(new VariableBinding(oid));
        }
        pdu.setType(PDU.GET);
        readResponse(sendPDU(pdu));
    }

    /**
     * 设置变更
     * @param variableBindings 变更绑定
     */
    public void setPDU(VariableBinding [] variableBindings) throws IOException {
        PDU pdu = new PDU();
        for(VariableBinding variableBinding:variableBindings){
            pdu.add(variableBinding);
        }
        pdu.setType(PDU.SET);
        //发送
        readResponse(sendPDU(pdu));
    }
    /**
     * 发送信息
     */
    public ResponseEvent sendPDU(PDU pdu) throws IOException {
        // 设置target
        CommunityTarget target = new CommunityTarget();
        //设置 团体名称
        target.setCommunity(new OctetString(agentCommunity));
        //设置地址
        target.setAddress(targetAddress);
        // 通信不成功时的重试次数
        target.setRetries(2);
        // 超时时间
        target.setTimeout(1500);
        //指定协议
        target.setVersion(SnmpConstants.version2c);
        // 向Agent发送PDU,并返回Response
        ResponseEvent event = snmp.send(pdu, target);
        //关闭
        snmp.close();
        return event;
    }

    /**
     * 读取信息
     * @param respEvnt
     */
    public void readResponse(ResponseEvent respEvnt) {
        // 解析Response
        if (respEvnt != null && respEvnt.getResponse() != null) {
           // System.out.println(respEvnt.getPeerAddress());
            System.out.println("【请求】"+respEvnt.getRequest());
            System.out.println("【返回】"+respEvnt.getResponse());
            Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getResponse().getVariableBindings();
            for (int i = 0; i < recVBs.size(); i++) {
                VariableBinding recVB = recVBs.elementAt(i);
                System.out.println(recVB.getOid() + " : " + recVB.getVariable());
            }
        }
    }
    ////////////////////////////////////////////////////////////
    private TransportMapping transport = null;
    public SnmpDemo(String agentAddress, String trapAddress, String agentCommunity)throws IOException {
        this.agentAddress=agentAddress;
        this.agentCommunity=agentCommunity;
        //监听地址
        this.trapAddress=trapAddress;
        this.initComm1();
    }
    public void initComm1() throws IOException {
        // 设置Agent方的IP和端口
        targetAddress = GenericAddress.parse(agentAddress);
        // 设置接收trap的IP和端口
        transport = new DefaultUdpTransportMapping(new UdpAddress(trapAddress));
        snmp = new Snmp(transport);
        CommandResponder trapRec = new CommandResponder() {
            @Override
            public synchronized void processPdu(CommandResponderEvent e) {
                // 接收trap
                PDU command = e.getPDU();
                if (command != null) {
                    System.out.println(command.toString());
                }
                VariableBinding value = null;
                /*Iterator<VariableBinding> size = command.getVariableBindings().iterator();
                while(size.hasNext()){
                    value = size.next();
                    System.out.println(value.getOid().toString()+" : "+value.getVariable().toString());
                }*/
            }
        };
        snmp.addCommandResponder(trapRec);
        transport.listen();
    }

    public synchronized void listen() {
        System.out.println("Waiting for traps..");
        try {
            this.wait();//Wait for traps to come in
        } catch (InterruptedException ex) {
            System.out.println("Interrupted while waiting for traps: " + ex);
            System.exit(-1);
        }
    }
}

分类
标签
snmp-example.zip 5.97K 36次下载
已于2022-6-1 21:22:21修改
6
收藏 1
回复
举报
1条回复
按时间正序
/
按时间倒序
码农修炼手册
码农修炼手册

学习了。

回复
2022-6-2 10:59:38
回复
    相关推荐