snmp4j 简介

模块 org.snmp4j

包org.snmp4j

该模块提供了用于创建、发送、接受snmp消息的类和接口。一个snmp消息由消息头和它的协议数据(PDU)报文组成。这个模块包含了三组主要类和接口:

  • 用于snmp消息、目标创建的类
  • 用于snmp消息发送的类
  • 用于snmp消息分发的类

下面的UML包图展示了核心snmp4j api包的依赖关系。使用这些api的用户一般只需要直接用org.snmp4j和org.snmp4j.smi这两个包

下面的UML类图展示了org.snmp4j包中的主要类以及这些类之间的关系(其他包中的类不在该图里面展示出来)。

 

SNMP消息和目标

和远程系统进行消息交互,这系统需要是明确指定的,重发、超时策略等消息相关的属性需要明确定义,snmp4j通过创建一个合适于使用snmp协议的目标实例来指定远程系统。

  • 对于SNMPv1和SNMPv2,CommunityTarget必须提供community信息,还有地址、重发、超时策略等目标接口定义的信息
  • 对于SNMPv3,则要用UserTarget替代,它扩展了SecureTarget抽象类并提供了基于用户安全模型的用户信息:安全名称、安全级别、安全模型和认证引擎ID

一个SNMP消息包含了消息体,协议数据单元(PDU)和消息头。简单的说,目标实例(Target instances)表示一个消息头,PDU则由下面的其中一个类来表示:

  • PDUv1(SNMPv1)
  • PDU(SNMPv2c)
  • ScopedPDU(SNMPv3)

这样,为了能够使用snmp4j来发送snmp消息,必须要创建一个PDU实例和Target实例

PDU例子(PDU Examples)

  • SNMPv1/v2c GETNEXT PDU
import org.snmp4j.PDU;
import org.snmp4j.smi.*;

...
PDU pdu = new PDU();
pdu.add(new VariableBinding(new OID("1.2.3.2.1.3")));
pdu.add(new VariableBinding(new OID("1.2.3.2.1.3")));
pdu.setType(PDU.GETNEXT);
...
  • SNMPv3 GETBULK PDU
ScopedPDU pdu = new ScopedPDU();
pdu.add(new VariableBinding(new OID("1.2.2.4.2.1.3")));
pdu.add(new VariableBinding(new OID("1.2.2.4.2.1.4")));
pdu.setType(PDU.GETBULK);
pdu.setMaxRepetitions(50);
pdu.setNonRepeaters(1);
pdu.setContextName(new OctetString("subSystemContextA"));
pdu.setContextEngineID(OctetString.fromHexString("80:00:13:70:c0:a8:01:0d"));
  • SNMPv1 TRAP PDU
PDUv1 pdu = new PDUv1();
pdu.setType(PDU.V1TRAP);
pdu.setGenericTrap(PDUv1.COLDSTART);
  • SNMPv2c/SNMPv3 INFORM PDU
long startTime = System.nanoTime();
ScopedPDU pdu = new ScopedPDU();
pdu.setType(PDU.INFORM);
// sysUpTime
long sysUpTime = (System.nanoTime() - startTime) / 10000000;  // 10^-7
pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(sysUpTime)));
pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, SnmpConstants.linkDown));
// payload
pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.2.1.1" + downIndex), new Integer32(downIndex)));

目标例子(Target Examples)

  • 社区目标(Community Target)
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
target.setVersion(SnmpConstants.version1);
  • 用户目标(User Target)
UserTarget target = new UserTarget();
target.setAddress(targetAddress);
target.setRetries(1);
// set timeout to 500 milliseconds: 2*500ms = 1s total timeout
target.setTimeout(500);
target.setVersion(SnmpConstants.version3);
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setSecurityName(new OctetString("MD5DES"));

发送SNMP消息

snmp4j通过使用SNMP会话接口的实例来发送snmp消息。这接口默认的实现类是Snmp类。

要创建Snmp实例,只需要用到一个TransportMapping实例,然后再调用其构造函数即可。

SNMP会话使用传输映射,通过传输协议(如用户数据报协议UDP)向远程系统发送(和接收)SNMP消息。

默认情况下,一个SNMP4J Snmp实例支持 SNMPv1、v2c和v3,通过对Snmp进行子分类,可以支持这些Snmp协议版本的其他组合。

在SNMP4J中,SNMP消息可以被同步(阻塞)和异步(非阻塞)发送。Snmp类不使用内部线程来处理异步和同步请求的响应。然而,它使用传输映射的接收器线程来处理响应。

异步响应通过对实现ResponseListener接口的对象实例调用回调方法返回。回调是在传输映射线程接收到响应包时执行的。因此,如果被调用的方法阻塞了,在传输映射的侦听端口上接收的同步和异步消息的传递也将被阻塞。其他传输映射不受影响。阻塞可以通过仅使用同步消息或者通过在回调方法中解耦处理来避免。

发送同步消息例子

Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
snmp.listen();
ResponseEvent response = snmp.send(requestPDU, target);
if (response.getResponse() == null) {
	// request timed out
} else {
	System.out.println("Received response from: " + response.getPeerAddress());
	// dump response PDU
	System.out.println(response.getResponse().toString());
}

发送异步消息例子

...
Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
snmp.listen();
...
ResponseListener listener = new ResponseListener() {
    public void onResponse(ResponseEvent event) {
       // Always cancel async request when response has been received
       // otherwise a memory leak is created! Not canceling a request
       // immediately can be useful when sending a request to a broadcast
       // address.
       ((Snmp)event.getSource()).cancel(event.getRequest(), this);
        PDU response = event.getResponse();
        PDU request = event.getRequest();
        if (response == null) {
            System.out.println("Request "+request+" timed out");
        }
        else {
            System.out.println("Received response "+response+" on request "+
                               request);
        }
    }
};
snmp.sendPDU(request, target, null, listener);
...

 

接收SNMP消息

SNM4J 通过监听传输映射端口接收snmp消息。为了能够接收响应或者请求,需要在监听器中设置好端口。这就需要通过调用TransportMapping实例的listen方法来启动传输映射内部监听线程。通过调用TransportMapping实例或者Snmp实例的close()方法来停止这个内部线程和监听端口。

传输映射只是以字节流的形式接收snmp消息,并将消息转发给关联的MessageDispatcher实例。默认情况下,SNMP4J使用MessageDispatcherImpl类的一个实例来解码和分派传入的消息。该实例由Snmp类在内部创建。

Snmp类处理对未完成请求的响应,并将其它Snmp消息的pdu转发到已注册的CommandResponder侦听器实例。因此,要接收snmp消息只需要:

  1. 创建一个TransportMapping并通过调用TransportMapping.listener()来初始化监听端口
  2. 使用上述的TransportMapping实例来创建一个Snmp实例
  3. 实例化一个CommandResponseder接口的类,并通过调用Snmp.addCommandResponder(CommandResponder)

当一个未处理的snmp消息(snmp消息中不存在相应的为解决请求)被接收到时,然后,CommandResponder的processPdu方法将被调用,其中包含已解码的pdu和由已解码的snmp消息

接收snmp消息例子

...
TransportMapping transport =
    new DefaultUdpTransportMapping(new UdpAddress("0.0.0.0/161"));
Snmp snmp = new Snmp(transport);
if (version == SnmpConstants.version3) {
    byte[] localEngineID =
        ((MPv3)snmp.getMessageProcessingModel(MessageProcessingModel.MPv3)).createLocalEngineID();
    USM usm = new USM(SecurityProtocols.getInstance(),
                      new OctetString(localEngineID), 0);
    SecurityModels.getInstance().addSecurityModel(usm);
    snmp.setLocalEngine(localEngineID, 0, 0);
    // Add the configured user to the USM
    ...
}
snmp.addCommandResponder(this);
snmp.listen();
...
public synchronized void processPdu(CommandResponderEvent e) {
    PDU command = e.getPdu();
    if (command != null) {
    ...
    }
}

参考: https://agentpp.com/doc/snmp4j/org/snmp4j/package-summary.html

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值