使用snmp4j實作trap告警
Snmp4j的trap處理的文章在網上看了一些不過都是淺嘗辄止,基本都是大概的講述了一下如何接收trap等簡單的技術。但是這些對于企業級的開發往往是不夠的,随着納入trap接收伺服器的裝置增加其接收到的trap資訊也是成級數增加的。這裡就需要我們對于這種大資料量的trap處理進行管理。本文不對trap的各種名詞進行解釋,需要有一定的snmp基礎知識及java程式設計知識了解。
一、整體設計思路
由于trap可能瞬時資料量特别的大,是以我們可以采用接收與處理互相分離的設計方法。即開啟一個線程專門接收trap,接收到trap後不做任何處理直接放入一個隊列中。然後開啟另一個線程從隊列中取資料,将取得的資料派發給多線程的處理接口處理。符合我們上報條件的trap向前台推送告警并讓前台頁面展現。具體流程如下圖。

二、示例程式搭建
本程式采用myeclipse開發,是以直接引用myeclipse的spring包即可。此外還需要snmp4j包,這裡就不提供下載下傳位址了。
執行個體項目第一版的目錄結構如下圖
a) spring 配置檔案applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="trapListener" class="com.hepan.listener.impl.SnmpTrapListener">
<property name="ip" value="192.168.122.34"></property>
<property name="port" value="162"></property>
</bean>
</beans>
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<CommandResponderEvent> trapQueue = new LinkedBlockingQueue<CommandResponderEvent>();
/**
* 獲得trap隊列
* @return CommandResponderEvent
*/
public static LinkedBlockingQueue<CommandResponderEvent> getRespEvntMsg (){
if(trapQueue==null){
return new LinkedBlockingQueue<CommandResponderEvent>();
}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();
}
}
f) 監聽具體實作方法類 SnmpTrapListener.java
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;
}
}
g) 處理實作類 SnmpTrapHandler.java
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後面我會陸續完成