SNMP trap(SNMP 陷阱):某种入口,到达该入口会使SNMP被管设备主动通知SNMP管理器,而不是等待SNMP管理器的再次轮询!
在网管系统中,被管理设备中的代理可以在任何时候向网络管理工作站报告错误情况,例如预制定阈值越界程度等等。代理并不需要等到管理工作站为获得这些错误情况而轮询他的时候才会报告。这些错误情况就是众所周知的SNMP自陷(trap)!
网管系统开放监听端口,始终监听被管设备对于该端口的通信信息。被管设备发生故障会主动向该端口发送故障信息,网管系统收到消息进行告警!
首先要模拟工作站对端口进行监听,请看如下程序:
Java代码
- package t3;
- import java.io.IOException;
- import java.net.UnknownHostException;
- import java.util.Vector;
- import org.snmp4j.CommandResponder;
- import org.snmp4j.CommandResponderEvent;
- import org.snmp4j.MessageDispatcherImpl;
- import org.snmp4j.Snmp;
- import org.snmp4j.TransportMapping;
- import org.snmp4j.mp.MPv1;
- import org.snmp4j.mp.MPv2c;
- import org.snmp4j.mp.MPv3;
- import org.snmp4j.security.SecurityModels;
- import org.snmp4j.security.SecurityProtocols;
- import org.snmp4j.security.USM;
- import org.snmp4j.smi.Address;
- import org.snmp4j.smi.GenericAddress;
- import org.snmp4j.smi.OctetString;
- import org.snmp4j.smi.TcpAddress;
- import org.snmp4j.smi.UdpAddress;
- import org.snmp4j.smi.VariableBinding;
- import org.snmp4j.transport.DefaultTcpTransportMapping;
- import org.snmp4j.transport.DefaultUdpTransportMapping;
- import org.snmp4j.util.MultiThreadedMessageDispatcher;
- import org.snmp4j.util.ThreadPool;
- /**
- * 本类用于监听代理进程的Trap信息
- */
- public class MultiThreadedTrapReceiver implements CommandResponder {
- public static void main(String[] args) {
- MultiThreadedTrapReceiver multithreadedtrapreceiver = new MultiThreadedTrapReceiver();
- multithreadedtrapreceiver.run();
- }
- private MultiThreadedMessageDispatcher dispatcher;
- private Snmp snmp = null;
- private Address listenAddress;
- private ThreadPool threadPool;
- public MultiThreadedTrapReceiver() {
- }
- public void run() {
- try {
- init();
- snmp.addCommandResponder(this);
- System.out.println("--------------->开始监听Trap信息!<---------------");
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- private void init() throws UnknownHostException, IOException {
- threadPool = ThreadPool.create("Trap", 2);
- dispatcher = new MultiThreadedMessageDispatcher(threadPool,new MessageDispatcherImpl());
- listenAddress = GenericAddress.parse(System.getProperty("snmp4j.listenAddress", "udp:127.0.0.1/2008")); // 本地IP与监听端口
- TransportMapping transport;
- // 对TCP与UDP协议进行处理
- if (listenAddress instanceof UdpAddress) {
- transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
- } else {
- transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
- }
- snmp = new Snmp(dispatcher, transport);
- snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
- snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
- snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
- USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
- SecurityModels.getInstance().addSecurityModel(usm);
- snmp.listen();
- }
- /**
- * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息
- * 当接收到trap时,会自动进入这个方法
- */
- @SuppressWarnings("unchecked")
- public void processPdu(CommandResponderEvent respEvnt) {
- // 解析Response
- if (respEvnt != null && respEvnt.getPDU() != null) {
- Vector<VariableBinding> recVBs = respEvnt.getPDU().getVariableBindings();
- for (int i = 0; i < recVBs.size(); i++) {
- VariableBinding recVB = recVBs.elementAt(i);
- System.out.println(recVB.getOid() + " : " + recVB.getVariable());
- }
- }
- }
- }
我们采用的是实现 CommandResponder 接口,该接口有一个方法
Java代码
- public void processPdu(CommandResponderEvent respEvnt)
在该端口接收到信息时会主动调用该方法!
运行Main方法,控制台提示
Java代码
- -------------->开始监听Trap信息!<---------------
程序对本机端口 2008 开始监听!
使用命令
Java代码
- >netstate -an
发现本机UDP端口已经开始监听!
我们再来实现Agent,被管设备向网管系统TRAP信息:
Java代码
- package t3;
- import java.io.IOException;
- import org.snmp4j.CommunityTarget;
- import org.snmp4j.PDU;
- import org.snmp4j.Snmp;
- import org.snmp4j.TransportMapping;
- 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;
- /**
- * 本类用于向管理进程发送Trap信息
- */
- public class SnmpUtilSendTrap {
- private Snmp snmp = null;
- private Address targetAddress = null;
- public static void main(String[] args) {
- try {
- SnmpUtilSendTrap util = new SnmpUtilSendTrap();
- util.initComm();
- util.sendPDU();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void initComm() throws IOException {
- // 设置管理进程的IP和端口
- targetAddress = GenericAddress.parse("udp:127.0.0.1/2008");
- TransportMapping transport = new DefaultUdpTransportMapping();
- snmp = new Snmp(transport);
- transport.listen();
- }
- /**
- * 向管理进程发送Trap报文
- *
- * @throws IOException
- */
- @SuppressWarnings("unchecked")
- public void sendPDU() throws IOException {
- // 设置 target
- CommunityTarget target = new CommunityTarget();
- target.setAddress(targetAddress);
- // 通信不成功时的重试次数
- target.setRetries(2);
- // 超时时间
- target.setTimeout(1000 * 5);
- // snmp版本
- target.setVersion(SnmpConstants.version2c);
- // 创建 PDU
- PDU pdu = new PDU();
- pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.1.6.0"),new OctetString("aaaa")));
- pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.1.2.0"),new OctetString("bbbb")));
- pdu.setType(PDU.TRAP);
- // 向Agent发送PDU,并接收Response
- snmp.send(pdu, target);
- System.out.println("------------> END<--------------");
- }
- }
使用的SNMP版本应该是 V2,V1的操作与V2 TRAP不同!
运行后控制台打印运行结束!
网管系统模拟端打印收到的OID和OID对应的值信息!
请您到ITEYE看我的原创:http://cuisuqiang.iteye.com
或支持我的个人博客,地址:http://www.javacui.com
1
顶
1
踩
分享到:
SNMP 使用SNMP4J V2进行同步和异步 GET, ... | 申请的群组通过了 Java研发交流 欢迎你
评论
7 楼 cuisuqiang 2014-06-04
KuhYygy 写道
请问下楼主,如果trap里的包含中文的信息,应该如何解码,准确来讲,应该如何选择字符编码?
String s = new String(((OctetString)recVB.getVariable()).getValue(), "UTF-8");
如上,我看有些写UTF-8,有些写GBK,请问这个应该怎么选择,或者有其它的方法解释出trap里的中文?谢谢~
如果是我们俩之间做通信,咱俩之间肯定知道字符串是什么编码格式的,为什么会出现不知道编码的情况?
6 楼 KuhYygy 2014-06-03
请问下楼主,如果trap里的包含中文的信息,应该如何解码,准确来讲,应该如何选择字符编码?
String s = new String(((OctetString)recVB.getVariable()).getValue(), "UTF-8");
如上,我看有些写UTF-8,有些写GBK,请问这个应该怎么选择,或者有其它的方法解释出trap里的中文?谢谢~
5 楼 lanqiu17 2014-02-21
cuisuqiang 写道
lanqiu17 写道
@SuppressWarnings("unchecked")
public void processPdu(CommandResponderEvent respEvnt) {
// 解析Response
if (respEvnt != null && respEvnt.getPDU() != null) {
Vector<VariableBinding> recVBs = respEvnt.getPDU().getVariableBindings();
for (int i = 0; i < recVBs.size(); i++) {
VariableBinding recVB = recVBs.elementAt(i);
System.out.println(recVB.getOid() + " : " + recVB.getVariable());
}
}
}
楼主,我觉得这里应该交给线程去处理。它占用的是接收trap线程池中的线程,会阻塞trap消息的接收
SNMP4J用的是堵塞线程池处理,既然已经有线程池处理了,为什么再做一层线程处理?除非是担心收到的消息很长时间处理不掉,那增大SNMP线程池就可以了
但当管理设备过多,并且发送trap消息频繁时,增大snmp线程池只是将问题延后了
4 楼 cuisuqiang 2014-02-20
lanqiu17 写道
@SuppressWarnings("unchecked")
public void processPdu(CommandResponderEvent respEvnt) {
// 解析Response
if (respEvnt != null && respEvnt.getPDU() != null) {
Vector<VariableBinding> recVBs = respEvnt.getPDU().getVariableBindings();
for (int i = 0; i < recVBs.size(); i++) {
VariableBinding recVB = recVBs.elementAt(i);
System.out.println(recVB.getOid() + " : " + recVB.getVariable());
}
}
}
楼主,我觉得这里应该交给线程去处理。它占用的是接收trap线程池中的线程,会阻塞trap消息的接收
SNMP4J用的是堵塞线程池处理,既然已经有线程池处理了,为什么再做一层线程处理?除非是担心收到的消息很长时间处理不掉,那增大SNMP线程池就可以了
3 楼 lanqiu17 2014-02-20
@SuppressWarnings("unchecked")
public void processPdu(CommandResponderEvent respEvnt) {
// 解析Response
if (respEvnt != null && respEvnt.getPDU() != null) {
Vector<VariableBinding> recVBs = respEvnt.getPDU().getVariableBindings();
for (int i = 0; i < recVBs.size(); i++) {
VariableBinding recVB = recVBs.elementAt(i);
System.out.println(recVB.getOid() + " : " + recVB.getVariable());
}
}
}
楼主,我觉得这里应该交给线程去处理。它占用的是接收trap线程池中的线程,会阻塞trap消息的接收
2 楼 lanqiu17 2014-02-20
哥们, 你也是做网管软件的啊 , 能交流下吗
1 楼 cuisuqiang 2012-06-05
如果Trap时需要给客户端返回一些信息,可以参考如下代码:
Java代码
- /**
- * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息
- * 当接收到trap时,会自动进入这个方法
- */
- @SuppressWarnings("unchecked")
- public void processPdu(CommandResponderEvent respEvnt) {
- List<VariableBinding> list = new ArrayList<VariableBinding>();
- // 解析Response
- if (respEvnt != null && respEvnt.getPDU() != null) {
- Vector<VariableBinding> recVBs = respEvnt.getPDU().getVariableBindings();
- for (int i = 0; i < recVBs.size(); i++) {
- VariableBinding recVB = recVBs.elementAt(i);
- System.out.println(recVB.getOid() + " : " + recVB.getVariable());
- Random random = new Random();
- list.add(new VariableBinding(recVB.getOid(),new Integer32(random.nextInt(1999))));
- }
- org.snmp4j.mp.StatusInformation statusInformation = new org.snmp4j.mp.StatusInformation();
- org.snmp4j.mp.StateReference ref = respEvnt.getStateReference();
- try {
- // 创建 PDU
- PDU vPDU = respEvnt.getPDU();
- vPDU.setType(PDU.RESPONSE);
- Random random = new Random();
- for(int i = 0;i< list.size() ;i++){
- VariableBinding vb = list.get(i);
- vb.setVariable(new Integer32(random.nextInt(9999)));
- vPDU.set(i,vb);
- }
- respEvnt.getMessageDispatcher().returnResponsePdu(
- respEvnt.getMessageProcessingModel(),
- respEvnt.getSecurityModel(),
- respEvnt.getSecurityName(),
- respEvnt.getSecurityLevel(),
- vPDU,
- respEvnt.getMaxSizeResponsePDU(),
- ref,
- statusInformation);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }