用snmp4j开发网管应用(二) -- 使用snmp4j

SNMP协议还算简单

其实针对协议的开发我们只要知道协议的内容,然后架起Socket服务器,然后用字符串拼出协议内容格式的字符串,使用Socket进行通信就好了。

针对协议的开源包主要把这些过程封装了。比如SNMP协议。

我们只需要针对PDU对象编程,然后SNMP4j就会把PDU对象转化为SNMP4j协议的格式,进行BER编码,然后传输,最后解码,再翻译为PDU对象。

先看一下SNMP协议要传输的内容:

http://www.cnpaf.net/Class/SNMP/200408/43.html

这个文章中说的很全和好了。接下来就是用SNMP4J协议的jar包来完成各个功能。

http://www.snmp4j.org/html/download.html

在这个网址中下载最新的SNMP4J的jar包,

或者是这个链接下载http://download.csdn.net/detail/three_man/7478029

顺便可以把SNMP4J-Agent-2.2-Instrumentation-Guide.pdf 这个文档描述了对Agent进行开发。

这个文档的下载链接:http://download.csdn.net/detail/three_man/7477953

SNMP4J把开发包分为了两个,一个SNMP4J.jar主要负责get,trap,set,一个是SNMP4J-Agent.jar主要负责作为一个网元被管理。

 

1 首先说一下怎么开发一个Agent.

 需要用到两个配置文件bc和cfg文件,可以在这里下载:http://download.csdn.net/detail/three_man/7477991

大概的代码为:

import java.io.File;  
import java.io.IOException;  
import java.util.ArrayList;  
import java.util.List;  
import org.snmp4j.agent.BaseAgent;  
import org.snmp4j.agent.CommandProcessor;  
import org.snmp4j.agent.DuplicateRegistrationException;  
import org.snmp4j.agent.io.ImportModes;  
import org.snmp4j.agent.mo.DefaultMOTable;  
import org.snmp4j.agent.mo.MOTableRow;  
import org.snmp4j.agent.mo.snmp.RowStatus;  
import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;  
import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;  
import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;  
import org.snmp4j.agent.mo.snmp.StorageType;  
import org.snmp4j.agent.mo.snmp.VacmMIB;  
import org.snmp4j.agent.security.MutableVACM;  
import org.snmp4j.mp.MPv3;  
import org.snmp4j.security.SecurityLevel;  
import org.snmp4j.security.SecurityModel;  
import org.snmp4j.security.USM;  
import org.snmp4j.smi.Integer32;  
import org.snmp4j.smi.OID;  
import org.snmp4j.smi.OctetString;  
import org.snmp4j.smi.Variable;  
  
public class MyAgent extends BaseAgent {  
    private List<DefaultMOTable> moTables = new ArrayList<DefaultMOTable>();  
    private String community;  
      
    protected MyAgent(File bootCounterFile, File configFile, List<DefaultMOTable> moTables, String community) {  
        super(bootCounterFile, configFile, new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));  
        this.moTables = moTables;  
        this.community = community;  
    }  
      
    @Override  
    protected void registerManagedObjects() {  
        try {  
            for (DefaultMOTable table : moTables) {  
                server.register(table, null);  
            }  
        } catch (DuplicateRegistrationException e) {  
            e.printStackTrace();  
        }  
    }  
      
    public void startUp(){  
        try {  
            this.init();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        this.loadConfig(ImportModes.REPLACE_CREATE);  
        this.addShutdownHook();  
        this.getServer().addContext(new OctetString(community));  
        this.finishInit();  
        this.run();  
        this.sendColdStartNotification();  
    }  
      
    /** 
     * to set community 
     */  
    @Override  
    protected void addCommunities(SnmpCommunityMIB communityMIB) {  
        Variable[] com2sec = new Variable[] {  
                new OctetString(community),                     // community name  
                new OctetString("cpublic"),                 // security name  
                getAgent().getContextEngineID(),            // local engine ID  
                new OctetString(community),                     // default context name  
                new OctetString(),                          // transport tag  
                new Integer32(StorageType.nonVolatile),     // storage type  
                new Integer32(RowStatus.active)             // row status  
        };  
        MOTableRow row =  
            communityMIB.getSnmpCommunityEntry().createRow(  
                    new OctetString("public2public").toSubIndex(true), com2sec);  
        communityMIB.getSnmpCommunityEntry().addRow(row);  
  
    }  
} 

  •  主要的代码是需要继承BaseAgent
  • 需要设置community
  • 需要注册Table,这个注册中的内容将是供给get和walk的内容。
  • 可以从MIB直接构建Agent,可能需要的包为:mibble-mibs是能够独MIB结构。这个也提供个下载地址吧: http://download.csdn.net/detail/three_man/7478061

2. Trap Receiver

   

import java.io.IOException;  
import java.util.logging.Logger;  
import org.snmp4j.MessageDispatcherImpl;  
import org.snmp4j.Snmp;  
import org.snmp4j.TransportMapping;  
import org.snmp4j.mp.MPv2c;  
import org.snmp4j.smi.Address;  
import org.snmp4j.smi.GenericAddress;  
import org.snmp4j.smi.UdpAddress;  
import org.snmp4j.transport.DefaultUdpTransportMapping;  
import org.snmp4j.util.MultiThreadedMessageDispatcher;  
import org.snmp4j.util.ThreadPool;  
import com.prince.snmp.tool.Command;  
import com.prince.snmp.tool.util.Configure;  
import com.prince.snmp.tool.util.Const;  
  
/** 
 * 构建一个多线程的Trap Receiver 
 * @author wangzijian 
 * 
 */  
public class SnmpReceiver implements Command{  
    private final Logger log = Logger.getLogger(SnmpReceiver.class.getName());  
  
    @Override  
    public void startUp() throws IOException {  
        log.info("Snmp Trap Receiver Start");  
        log.info("listened on " + Configure.getInstance().getUdpTrapIpPort());  
        ThreadPool pool = ThreadPool.create(Const.THREAD_POOL_NAME, Const.AGENT_THREAD_NUM);  
        MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(pool, new MessageDispatcherImpl());  
        Address listenAddress = GenericAddress.parse(Configure.getInstance().getUdpTrapIpPort());  
        TransportMapping transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);  
        // 构建SNMP,并且使其开始监听  
        Snmp snmp = new Snmp(dispatcher, transport);  
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());  
        snmp.listen();  
        snmp.addCommandResponder(new CommandResponderImpl());  
    }  
}  

package com.prince.snmp.tool.receiver;  
  
import java.util.List;  
import java.util.logging.Logger;  
import org.snmp4j.CommandResponder;  
import org.snmp4j.CommandResponderEvent;  
import org.snmp4j.PDU;  
import org.snmp4j.smi.OID;  
import org.snmp4j.smi.VariableBinding;  
  
public class CommandResponderImpl implements CommandResponder {  
    private final Logger log = Logger.getLogger(CommandResponderImpl.class.getName());  
      
    @Override  
    public void processPdu(CommandResponderEvent event) {  
        PDU pdu = event.getPDU();  
        if(PDU.TRAP == pdu.getType()){  
            operate(pdu);  
        }else{  
            log.info("pdu method is:" + pdu.getType() + " not a trap");  
        }  
          
    }  
  
    private void operate(PDU pdu) {  
        List<VariableBinding> bindings = pdu.getBindingList(new OID(".1"));  
          
        for (VariableBinding binding : bindings) {  
            System.out.println(binding.getOid() + "====" + binding.getVariable().toString());  
        }  
    }  
}  

  •  需要一个多线程的服务器MultiThreadedMessageDispatcher
  • 还需要一个处理类 CommandResponderImpl  snmp.addCommandResponder
  • 在处理类中能够得到PDU,这个类不只可以作为Receiver还能够开发为Agent,但是需要自己来写很多逻辑,还有可能用到文件或者内存数据库
3. send trap

package com.prince.snmp.tool.trap;  
  
import java.io.IOException;  
import java.lang.reflect.InvocationTargetException;  
import java.util.List;  
import java.util.Vector;  
import org.snmp4j.CommunityTarget;  
import org.snmp4j.PDU;  
import org.snmp4j.Snmp;  
import org.snmp4j.TransportMapping;  
import org.snmp4j.event.ResponseEvent;  
import org.snmp4j.smi.Address;  
import org.snmp4j.smi.GenericAddress;  
import org.snmp4j.smi.OctetString;  
import org.snmp4j.smi.UdpAddress;  
import org.snmp4j.smi.VariableBinding;  
import org.snmp4j.transport.DefaultUdpTransportMapping;  
import com.prince.snmp.tool.Command;  
import com.prince.snmp.tool.trap.dataGenerator.ITrapGenerator;  
import com.prince.snmp.tool.util.Configure;  
  
public class TrapSender implements Command{  
    private Snmp snmp;  
    private Address targetAddress;  
    private ITrapGenerator generator;  
      
    public TrapSender(ITrapGenerator generator) {  
        this.generator = generator;  
        targetAddress = GenericAddress.parse(Configure.getInstance().getUdpTrapIpPort());  
        TransportMapping<UdpAddress> transport = null;  
        try {  
            transport = new DefaultUdpTransportMapping();  
            snmp = new Snmp(transport);  
            transport.listen();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
      
    public void sendTrap(){  
        CommunityTarget target = new CommunityTarget();  
        target.setAddress(targetAddress);  
        target.setRetries(Configure.getInstance().getRetries());  
        target.setTimeout(Configure.getInstance().getTimeOut());  
        target.setCommunity(new OctetString(Configure.getInstance().getCommunity()));  
        target.setVersion(Configure.getInstance().getSnmpVersion());  
          
        List<TrapData> datas = generator.generateTrapData();  
          
        try {  
            for (TrapData trapData : datas) {  
                sendPdu(trapData, target);  
            }  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        } catch (InvocationTargetException e) {  
            e.printStackTrace();  
        } catch (NoSuchMethodException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
      
    private void sendPdu(TrapData trapData, CommunityTarget target) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {  
        PDU pdu = MoToPdu.moToPdu(trapData);  
        ResponseEvent respEvnt = snmp.send(pdu, target);  
          
        // 解析Response    
        if (respEvnt != null && respEvnt.getResponse() != null) {    
            Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getResponse().getVariableBindings();    
            for (int i = 0; i < recVBs.size(); i++) {    
                VariableBinding recVB = recVBs.elementAt(i);    
                System.out.println(recVB.getOid() + " : " + recVB.getVariable());    
            }    
        }  
    }  
  
      
}  

  •   trap主要注意必须设置两个VariableBingding

                pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(trap.getSysUpTime())));

 

                pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(trap.getTrapOid())))

4. get
private static void simpleGet() throws IOException {  
    TransportMapping<UdpAddress> transport = new DefaultUdpTransportMapping();  
    Snmp snmp = new Snmp(transport);  
    transport.listen();  
      
    CommunityTarget target = new CommunityTarget();   
    target.setCommunity(new OctetString("CONV"));  
    Address targetAddress = GenericAddress.parse("udp:10.141.43.237/161");   
    target.setAddress(targetAddress);  
    target.setRetries(3);  
    target.setTimeout(3000);  
    target.setVersion(SnmpConstants.version2c);  
      
    PDU pdu = new PDU();    
       pdu.add(new VariableBinding(new OID(".1.3.6.1.4.1.7569.1.2.1.23.3.1")));    
       pdu.setType(PDU.GETBULK);  
       pdu.setMaxRepetitions(20);  
       pdu.setNonRepeaters(0);  
         
       ResponseEvent respEvnt = snmp.send(pdu, target);    
       if (respEvnt != null && respEvnt.getResponse() != null) {    
              Vector<VariableBinding> recVBs = (Vector<VariableBinding>) respEvnt.getResponse().getVariableBindings();    
              for (int i = 0; i < recVBs.size(); i++) {    
                     VariableBinding recVB = recVBs.elementAt(i);    
                     System.out.println(recVB.getOid() + " : " + recVB.getVariable());    
  
              }    
  
       }    
}  
  •      get相对于比较简单,资料也比较多。主要是设定pdu.setType(PDU.GETBULK);
  • 利用getnext和一些判断可以实现walk.
  • http://blog .sina.com.cn/s/blog_6cb15f8f0100yx4p.html 这个哥们儿写得非常好

具体的代码没有写,因为下一篇会共享一个小的工具,可以以配置文件为基础来构建Receiver,发送Trap,构建Agent等。



上一篇:【漫画】为什么MySQL数据库要用B+树存储索引?


下一篇:开发指南—运算符—算术运算符