snmp4j

Java中的snmp客户端是snmp4j,使用maven将其导入:

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

实体

下面是在snmp4j包中我们会用到的实体:

  • Snmp:代表一个snmp实例,我们用它来向远程主机发送请求。
  • CommunityTarget:即社区,我们需要对它进行配置。
  • PDU:数据协议单元。
  • ResponseEvent:代表一个返回事件,里面有请求体,返回体,错误信息等
  • TransportMapping:在snmp4j中代表传输层的协议。

初始化

    /**
     * 初始化snmp以及Target
     */
    public static void initSnmp() throws IOException {
        target = new CommunityTarget();
        // 设置团体
        target.setCommunity(new OctetString("private"));
        // 设置远程主机的地址
        target.setAddress(new UdpAddress("127.0.0.1/161"));
        // 设置重试次数
        target.setRetries(1);
        // 设置超时时间
        target.setTimeout(3000);
        // 设置使用的snmp版本
        target.setVersion(SnmpConstants.version2c);
        /**
         * 初始化snmp
         * 在snmp4j中,使用{@link org.snmp4j.TransportMapping}来表示传输层的协议。
         * 可以增加多个TransportMapping来支持多种协议(TCP UDP SSH):snmp.addTransportMapping(new DefaultTcpTransportMapping());
         * 底层是启动了多个线程来监听不同的端口,从而支持多种协议。
         * new DefaultUdpTransportMapping()如果不带参数代表随机一个使用一个本地ip+端口,
         * 如果想要指定本地ip+端口,可以使用new DefaultUdpTransportMapping(new UdpAddress("127.0.0.1/8888"));
         */
        snmp = new Snmp(new DefaultUdpTransportMapping());
        // 遍历所有的Mapping,开启监听
        snmp.listen();
    }

上面是对CommunityTarget和snmp的初始化,CommunityTarget需要我们设置团体名,远程主机的地址,重试次数,超时时间。

snmp的初始化见代码,如果不需要多个协议,只需要写snmp = new Snmp(new DefaultUdpTransportMapping());这一行即可

发送消息

/**
     * 发送消息
     *
     * @param pdu {@link PDU}
     */
public static void sendSnmpRequest(PDU pdu) throws Exception{
    // 发送PDU 并且接收响应事件
    ResponseEvent responseEvent = snmp.send(pdu, target);
    // 解析响应,获取返回值
    PDU response = responseEvent.getResponse();
    // 判断请求是否出错,如timeOut,远程地址错误
    if (responseEvent.getError() != null || response == null){
        System.out.println("Operation Error:" + responseEvent.getError());
    } else {
        // 判断返回值是否有错,如noSuchObject
        if (response.getErrorStatus() == PDU.noError) {
            // 输出变量绑定表
            Vector<? extends VariableBinding> vbs = response.getVariableBindings();
            for (VariableBinding vb : vbs) {
                System.out.println(vb + " , type is " + vb.getVariable().getSyntaxString());
            }
        } else {
            System.out.println("Response Error:" + response.getErrorStatusText());
        }
    }
}

此方法接收一个PDU,使用初始化好的communityTarget发送,下面的set get get-next get-bulk都使用这个方法发送消息,解释见上面的注释。

主循环

public static void main(String[] args) {
    try {
        // 初始化
        initSnmp();
        while(true) {
            // 根据不同的类型发送不同的消息
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入OID:");
            String oid = scanner.nextLine();
            System.out.println("请输入选项:");
            System.out.println("1.set");
            System.out.println("2.get");
            System.out.println("3.getNext");
            System.out.println("4.getBulk");
            int type = scanner.nextInt();
            switch (type) {
                case 1 -> {
                    System.out.println("请输入值:");
                    scanner = new Scanner(System.in);
                    String val = scanner.nextLine();
                    System.out.println("val = " + val);
                    SnmpSet(oid,val);
                }
                case 2 -> SnmpGet(oid);
                case 3 -> SnmpGetNext(oid);
                case 4 -> {
                    System.out.println("请输入数量:");
                    scanner = new Scanner(System.in);
                    int num = scanner.nextInt();
                    SnmpGetBulk(oid,num);
                }
                default -> {
                    System.out.println("输入错误");
                    return;
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

创建一个无线循环不断的执行用户的操作。

Set

public static void SnmpSet(String oid,String val) throws Exception {
    PDU pdu = new PDU();
    pdu.setType(PDU.SET);
    pdu.add(new VariableBinding(new OID(oid), new OctetString(val)));
    sendSnmpRequest(pdu);
}

初始化一个PDU,设置类型为set,在PDU中可以加入多个要操作的变量,然后发送。

Get

public static void SnmpGet(String oid) throws Exception{
    PDU pdu = new PDU();
    pdu.setType(PDU.GET);
    pdu.add(new VariableBinding(new OID(oid)));
    sendSnmpRequest(pdu);
}

初始化一个PDU,设置类型为get,然后发送。

Get-Next

public static void SnmpGetNext(String oid) throws Exception{
    PDU pdu = new PDU();
    pdu.setType(PDU.GETNEXT);
    pdu.add(new VariableBinding(new OID(oid)));
    sendSnmpRequest(pdu);
}

初始化一个PDU,设置类型为get-next,然后发送。

Get-Bulk

public static void SnmpGetBulk(String oid,int number) throws Exception{
    PDU pdu = new PDU();
    pdu.setType(PDU.GETBULK);
    pdu.setMaxRepetitions(number);
    pdu.add(new VariableBinding(new OID(oid)));
    sendSnmpRequest(pdu);
}

初始化一个PDU,设置类型为get-bulk,同时可以设置我们想要一次性获取的数量,然后发送。

代码

package com.zzys.snmp;

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.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;

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

/**
 * MySnmp
 *
 * @author YangZhang
 * @createTime 2023/12/05/ 12:50
 */
public class MySnmp {
    private static CommunityTarget target;
    private static Snmp snmp;

    public static void main(String[] args) {
        try {
            // 初始化
            initSnmp();
            while(true) {
                // 根据不同的类型发送不同的消息
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入OID:");
                String oid = scanner.nextLine();
                System.out.println("请输入选项:");
                System.out.println("1.set");
                System.out.println("2.get");
                System.out.println("3.getNext");
                System.out.println("4.getBulk");
                int type = scanner.nextInt();
                switch (type) {
                    case 1 -> {
                        System.out.println("请输入值:");
                        scanner = new Scanner(System.in);
                        String val = scanner.nextLine();
                        System.out.println("val = " + val);
                        SnmpSet(oid,val);
                    }
                    case 2 -> SnmpGet(oid);
                    case 3 -> SnmpGetNext(oid);
                    case 4 -> {
                        System.out.println("请输入数量:");
                        scanner = new Scanner(System.in);
                        int num = scanner.nextInt();
                        SnmpGetBulk(oid,num);
                    }
                    default -> {
                        System.out.println("输入错误");
                        return;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void SnmpSet(String oid,String val) throws Exception {
        PDU pdu = new PDU();
        pdu.setType(PDU.SET);
        pdu.add(new VariableBinding(new OID(oid), new OctetString(val)));
        sendSnmpRequest(pdu);
    }
    public static void SnmpGet(String oid) throws Exception{
        PDU pdu = new PDU();
        pdu.setType(PDU.GET);
        pdu.add(new VariableBinding(new OID(oid)));
        sendSnmpRequest(pdu);
    }

    public static void SnmpGetBulk(String oid,int number) throws Exception{
        PDU pdu = new PDU();
        pdu.setType(PDU.GETBULK);
        pdu.setMaxRepetitions(number);
        pdu.add(new VariableBinding(new OID(oid)));
        sendSnmpRequest(pdu);
    }

    public static void SnmpGetNext(String oid) throws Exception{
        PDU pdu = new PDU();
        pdu.setType(PDU.GETNEXT);
        pdu.add(new VariableBinding(new OID(oid)));
        sendSnmpRequest(pdu);
    }

    /**
     * 发送消息
     *
     * @param pdu {@link PDU}
     */
    public static void sendSnmpRequest(PDU pdu) throws Exception{
        // 发送PDU 并且接收响应事件
        ResponseEvent responseEvent = snmp.send(pdu, target);
        // 解析响应,获取返回值
        PDU response = responseEvent.getResponse();
        // 判断请求是否出错,如timeOut,远程地址错误
        if (responseEvent.getError() != null || response == null){
            System.out.println("Operation Error:" + responseEvent.getError());
        } else {
            // 判断返回值是否有错,如noSuchObject
            if (response.getErrorStatus() == PDU.noError) {
                // 输出变量绑定表
                Vector<? extends VariableBinding> vbs = response.getVariableBindings();
                for (VariableBinding vb : vbs) {
                    System.out.println(vb + " , type is " + vb.getVariable().getSyntaxString());
                }
            } else {
                System.out.println("Response Error:" + response.getErrorStatusText());
            }
        }
    }

    /**
     * 初始化snmp以及Target
     */
    public static void initSnmp() throws IOException {
        target = new CommunityTarget();
        // 设置团体
        target.setCommunity(new OctetString("private"));
        // 设置远程主机的地址
        target.setAddress(new UdpAddress("127.0.0.1/161"));
        // 设置重试次数
        target.setRetries(1);
        // 设置超时时间
        target.setTimeout(3000);
        // 设置使用的snmp版本
        target.setVersion(SnmpConstants.version2c);
        /**
         * 初始化snmp
         * 在snmp4j中,使用{@link org.snmp4j.TransportMapping}来表示传输层的协议。
         * 可以增加多个TransportMapping来支持多种协议(TCP UDP SSH):snmp.addTransportMapping(new DefaultTcpTransportMapping());
         * 底层是启动了多个线程来监听不同的端口,从而支持多种协议。
         * new DefaultUdpTransportMapping()如果不带参数代表随机一个使用一个本地ip+端口,
         * 如果想要指定本地ip+端口,可以使用new DefaultUdpTransportMapping(new UdpAddress("127.0.0.1/8888"));
         */
        snmp = new Snmp(new DefaultUdpTransportMapping());
        // 遍历所有的Mapping,开启监听
        snmp.listen();
    }
}
上次更新:
Contributors: YangZhang