java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java发送SNMP至交换机获取交换机状态

Java发送SNMP至交换机获取交换机状态实现方式

作者:嚯呀怪怪怪

文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v3的安全性差异,并说明通过PDU封装请求及GETBULK操作提升数据获取效率

交换机协议

这里使用的交换机协议为常见的RCF1213-MIB协议,使用SNMP协议与交换机进行通信。前提记得开启交换机对于SNMP协议的支持

SNMP库

使用SNMP4J库进行开发,maven提供了相应的pom,笔者使用的版本为2.7.0。pom内容如下

    <!-- snmp4j依赖包 -->
    <dependency>
        <groupId>org.snmp4j</groupId>
        <artifactId>snmp4j</artifactId>
        <version>2.7.0</version>
    </dependency>

获取交换机单路状态

首先明确交换机所在的IP地址,交换机提供的公共团体名称以及对应的OID

团体名称简单的来说就是验证码

如果 A 要访问B 的核心内容A 必须有B 的公钥,在和B 通信的时候B 也必须能认证A 持有的公钥

这个过程中的公钥和SNMP的团体名称功能类似

		// 配置交换机的SNMP参数
		// 交换机的IP地址
        String ipAddress = "192.168.1.1";
        // 公共团体名称
        String community = "public";
        // RFC1213-MIB中的ifOperStatus OID,用于获取接口的操作状态
        String oidValue = "1.3.6.1.2.1.2.2.1.8";

第二步设定好目标地址以及基础的超时重试信息

其中SNMP协议一共有三个版本,第一代能力欠缺,第三代还处于测试阶段,因此使用能力较为丰富且稳定的第二代SNMP协议。

		// 创建目标地址。这里使用的是UDP协议,并指定了交换机的IP地址和SNMP端口161。
        Address targetAddress = GenericAddress.parse("udp:" + ipAddress + "/161");
        // 创建一个社区目标对象,用于存储SNMP的目标信息。        
        CommunityTarget target = new CommunityTarget();
        // 设置目标的社区字符串。这里使用的是"public"。
        target.setCommunity(new OctetString(community));
        // 设置目标的地址,即前面创建的目标地址。
        target.setAddress(targetAddress);
        // 设置请求失败时的重试次数,这里设置为2次。
        target.setRetries(2);
        // 设置请求的超时时间,单位为毫秒,这里设置为1500毫秒(1.5秒)。
        target.setTimeout(1500);
        // 设置SNMP的版本,这里使用的是SNMP v2c。
        target.setVersion(SnmpConstants.version2c);

第三步创建TransportMapping并监听SNMP的返回值

第三步主要通过PDU这个对象单元来进行数据的交换。

一个PDU(Protocol Data Unit)对象,用于封装SNMP请求。

		try {
			// 创建UDP传输映射,用于SNMP通信。
            TransportMapping<?> transport = new DefaultUdpTransportMapping();
            // 监听传输映射,即启动SNMP传输。
            transport.listen();
			// 创建一个Snmp对象,用于发送和接收SNMP消息
            Snmp snmp = new Snmp(transport);
            // 创建PDU
            PDU pdu = new PDU();
            // 创建一个PDU(Protocol Data Unit)对象,用于封装SNMP请求。
            pdu.add(new VariableBinding(new OID(oidValue)));
             // 设置PDU的类型为GETNEXT,用于获取单个变量。
            pdu.setType(PDU.GETNEXT);     
            // 发送请求
            boolean finished = false;
            while (!finished) {
            	// 发送SNMP请求,并接收响应事件。
                ResponseEvent responseEvent = snmp.send(pdu, target);
                 // 获取响应PDU。
                PDU responsePDU = responseEvent.getResponse();
                .............
            	.............  
            }
            snmp.close();
            // 关闭SNMP对象,释放资源。
        } catch (Exception e) {
            e.printStackTrace();
            // 捕获并打印异常。
        }

第四步处理我们请求的返回值

if (responsePDU != null) {
    for (VariableBinding vb : responsePDU.getVariableBindings()) {
    	// 检查响应中的OID是否属于请求的OID范围。
        if (vb.getOid().toString().startsWith(oidValue)) {
             // 打印OID及其对应的变量值。
            System.out.println(vb.getOid() + " = " + vb.getVariable());
            // 重置请求ID。
            pdu.setRequestID(new Integer32(0));
          // 将PDU的第一个变量设置为上次收到的OID,以获取下一个变量。
            pdu.set(0, vb);  
        } else {
         	// 如果OID不再属于请求的范围,则完成循环。
            finished = true;
            break;
        }
    }
} else {
    finished = true;
    // 如果响应PDU为空,则完成循环。
}

完整代码如下

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
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;

public class SnmpGet {

    public static void main(String[] args) {
        // 配置交换机的SNMP参数
         // 交换机的IP地址
        String ipAddress = "192.168.1.1";
         // 公共团体名称
        String community = "public";
        // RFC1213-MIB中的ifOperStatus OID,用于获取接口的操作状态
        String oidValue = "1.3.6.1.2.1.2.2.1.8"; 

        // 创建目标
        Address targetAddress = GenericAddress.parse("udp:" + ipAddress + "/161");
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(targetAddress);
        target.setRetries(2);
        target.setTimeout(1500);
        target.setVersion(SnmpConstants.version2c);

        // 创建TransportMapping并监听
        try {
            TransportMapping<?> transport = new DefaultUdpTransportMapping();
            transport.listen();
            Snmp snmp = new Snmp(transport);

            // 创建PDU
            PDU pdu = new PDU();
            pdu.add(new VariableBinding(new OID(oidValue)));
            pdu.setType(PDU.GETNEXT);

            // 发送请求
            ResponseEvent responseEvent = snmp.send(pdu, target);
            PDU responsePDU = responseEvent.getResponse();

            if (responsePDU != null) {
                for (VariableBinding vb : responsePDU.getVariableBindings()) {
                    System.out.println(vb.getOid() + " = " + vb.getVariable());
                }
            } else {
                System.out.println("响应PDU为空");
            }

            snmp.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

获取交换机多路状态

关键点就在于修改PDU的属性设置,其他同单路一样。

SNMP的GETBULK操作来获取多个结果,可以提高获取大量信息的效率。

pdu.setType(PDU.GETBULK);
 // 每次请求的最大重复次数
pdu.setMaxRepetitions(10);
 // 非重复计数器
pdu.setNonRepeaters(0);

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

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