使用snmp4j实现trap告警
Snmp4j的trap处理的文章在网上看了一些不过都是浅尝辄止,基本都是大概的讲述了一下如何接收trap等简单的技术。但是这些对于企业级的开发往往是不够的,随着纳入trap接收服务器的设备增加其接收到的trap信息也是成级数增加的。这里就需要我们对于这种大数据量的trap处理进行管理。本文不对trap的各种名词进行解释,需要有一定的snmp基础知识及java编程知识理解。
一、整体设计思路
由于trap可能瞬时数据量特别的大,所以我们可以采用接收与处理相互分离的设计方法。即开启一个线程专门接收trap,接收到trap后不做任何处理直接放入一个队列中。然后开启另一个线程从队列中取数据,将取得的数据派发给多线程的处理接口处理。符合我们上报条件的trap向前台推送告警并让前台页面展现。具体流程如下图。
二、示例程序搭建
本程序采用myeclipse开发,所以直接引用myeclipse的spring包即可。此外还需要snmp4j包,这里就不提供下载地址了。
实例项目第一版的目录结构如下图
a) spring 配置文件applicationContext.xml
b)main方法类Start.java
package com.hepan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hepan.handler.SnmpTrapHandler;
import com.hepan.listener.impl.SnmpTrapListener;
/**
* 启动类
* @author 何盼
*
*/
public class Start {
public static ApplicationContext fsxac;
public static void main(String[] args) {
fsxac = new ClassPathXmlApplicationContext("applicationContext.xml");
//启动处理线程
new Thread(new SnmpTrapHandler()).start();
//启动监听线程
new Thread((SnmpTrapListener)fsxac.getBean("trapListener")).start();
}
}
c) 队列中心 QueueCenter.java
package com.hepan.queue;
import java.util.concurrent.LinkedBlockingQueue;
import org.snmp4j.CommandResponderEvent;
/**
* 队列中心存放原始trap记录即接收到的CommandResponderEvent对象
* @author 何盼
*
*/
public class QueueCenter {
private static LinkedBlockingQueue trapQueue = new LinkedBlockingQueue();
/**
* 获得trap队列
* @return CommandResponderEvent
*/
public static LinkedBlockingQueue getRespEvntMsg (){
if(trapQueue==null){
return new LinkedBlockingQueue();
}else{
return trapQueue;
}
}
/**
* 存入trap队列
* @param message
* @throws InterruptedException
*
*
*/
public static void putRespEvntLogsQueue(CommandResponderEvent message) throws InterruptedException{
trapQueue.put(message);
}
}
d) 监听接口ListenerInterface.java
package com.hepan.listener;
import org.snmp4j.CommandResponderEvent;
/**
* 接收trap信息类接口定义
* @author 何盼
*
*/
public interface ListenerInterface {
/**
* 存入队列方法
* @param respEvnt
*/
public void putMessage2Queue(CommandResponderEvent respEvnt );
/**
* 初始化方法初始化监听端口、ip等信息,这些信息需要从SPRING配置文件中读取
*/
public void init();
}
d) 监听抽象AbstListener .java
package com.hepan.listener;
import org.snmp4j.CommandResponderEvent;
import com.hepan.queue.QueueCenter;
/**
* 处理类的抽象方法
*
* @author 何盼
*
*/
public abstract class AbstListener implements ListenerInterface ,Runnable {
@Override
public void putMessage2Queue(CommandResponderEvent respEvnt) {
try {
QueueCenter.putRespEvntLogsQueue(respEvnt);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
init();
}
}
package com.hepan.listener.impl;
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.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import com.hepan.listener.AbstListener;
/**
* 监听类
* @author 何盼
*
*/
public class SnmpTrapListener extends AbstListener implements CommandResponder{
private String ip; //本地IP
private String port; //监听端口
private Address listenAddress; //地址信息
private ThreadPool threadPool;
private MultiThreadedMessageDispatcher dispatcher;
@Override
public void init() {
try{
threadPool=ThreadPool.create("Trap", 2);
dispatcher=new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
listenAddress = GenericAddress.parse(System.getProperty(
"snmp4j.listenAddress", "udp:" + ip + "/" + port));
TransportMapping transport;
// 对TCP与UDP协议进行处理
if (listenAddress instanceof UdpAddress) {
transport = new DefaultUdpTransportMapping(
(UdpAddress) listenAddress);
} else {
transport = new DefaultTcpTransportMapping(
(TcpAddress) listenAddress);
}
Snmp 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();
snmp.addCommandResponder(this);
System.out.println("启动监听成功");
}catch (Exception e){
System.out.println("snmp 初始化失败");
e.printStackTrace();
}
}
//此方法为CommandResponder 接口实现方法用于监听后的处理方法,将接收到的trap信息入队
@Override
public void processPdu(CommandResponderEvent CREvent) {
System.out.println("in processPdu");
this.putMessage2Queue(CREvent);
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public Address getListenAddress() {
return listenAddress;
}
public void setListenAddress(Address listenAddress) {
this.listenAddress = listenAddress;
}
}
package com.hepan.handler;
import org.snmp4j.CommandResponderEvent;
import com.hepan.queue.QueueCenter;
/**
* 处理类
* @author 何盼
*
*/
public class SnmpTrapHandler implements Runnable{
@Override
public void run() {
while(true){
try {
CommandResponderEvent resEvent=QueueCenter.getRespEvntMsg().take();
System.out.println("event:"+resEvent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
三、测试trap接收
a)首先启动程序,运行Start.java得到如图所示。
b)发送trap
发送trap我们采用ibm为我们提供的SolarWinds的Trap Editor软件,界面如下图。
新建一个trap,然后点击发送按钮。如图下图所示。
填入IP后即可发送模拟trap了,程序收到这条信息后控制台的输出结果如下图说是
对于如何处理该条trap后面我会陆续完成