天天看點

Snmp4j程式設計簡介之三:snmp

Snmp4j程式設計簡介之三:Snmp

Class Snmp

java.lang.Object

  org.snmp4j.Snmp

All Implemented Interfaces:

java.util.EventListener, CommandResponder, Session

     snmp類是SNMP4J的核心,它提供了發送和接收SNMP PDUs的方法,所有的SNMP PDU 類型都可以采用同步或者異步的方式被發送。

    Snmp采用獨立的傳輸協定,通過TransportMapping 接口調用addTransportMapping(TransportMapping transportMapping) 方法或者采用預設的構造函數來實作傳輸映射,以此來實作資訊的傳輸。

  下面的代碼片段是采用UDP傳輸方式來實作一個SNMPv3的SNMP session :

Java代碼

Address targetAddress = GenericAddress.parse("udp:127.0.0.1/161");  

   TransportMapping transport = new DefaultUdpTransportMapping();  

   snmp = new Snmp(transport);  

   USM usm = new USM(SecurityProtocols.getInstance(),  

                     new OctetString(MPv3.createLocalEngineID()), 0);  

   SecurityModels.getInstance().addSecurityModel(usm);  

   transport.listen(); 

Address targetAddress = GenericAddress.parse("udp:127.0.0.1/161");

   TransportMapping transport = new DefaultUdpTransportMapping();

   snmp = new Snmp(transport);

   USM usm = new USM(SecurityProtocols.getInstance(),

                     new OctetString(MPv3.createLocalEngineID()), 0);

   SecurityModels.getInstance().addSecurityModel(usm);

   transport.listen();

如何實作SNMPv3資訊的同步發送,下面舉例說明:

Java代碼

// add user to the USM  

   snmp.getUSM().addUser(new OctetString("MD5DES"),  

                         new UsmUser(new OctetString("MD5DES"),  

                                     AuthMD5.ID,  

                                     new OctetString("MD5DESUserAuthPassword"),  

                                     PrivDES.ID,  

                                     new OctetString("MD5DESUserPrivPassword")));  

   // create the target  

   UserTarget target = new UserTarget();  

   target.setAddress(targetAddress);  

   target.setRetries(1);  

   target.setTimeout(5000);  

   target.setVersion(SnmpConstants.version3);  

   target.setSecurityLevel(SecurityLevel.AUTH_PRIV);  

   target.setSecurityName(new OctetString("MD5DES"));  

   // create the PDU  

   PDU pdu = new ScopedPDU();  

   pdu.add(new VariableBinding(new OID("1.3.6")));  

   pdu.setType(PDU.GETNEXT);  

   // send the PDU  

   ResponseEvent response = snmp.send(pdu, target);  

   // extract the response PDU (could be null if timed out)  

   PDU responsePDU = response.getResponse();  

   // extract the address used by the agent to send the response:  

   Address peerAddress = response.getPeerAddress();  

 An asynchronous SNMPv1 request is sent by the following code:   

   // setting up target  

   CommunityTarget target = new CommunityTarget();  

   target.setCommunity(new OctetString("public"));  

   target.setAddress(targetAddress);  

   target.setRetries(2);  

   target.setTimeout(1500);  

   target.setVersion(SnmpConstants.version1);  

   // creating PDU  

   PDU pdu = new PDU();  

   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,1})));  

   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,2})));  

   pdu.setType(PDU.GETNEXT);  

   // sending request  

   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);  

       System.out.println("Received response PDU is: "+event.getResponse());  

     }  

   };  

   snmp.sendPDU(pdu, target, null, listener);  

//Traps (notifications) and other SNMP PDUs can be received by adding the folling code to the first code snippet above:   

   CommandResponder trapPrinter = new CommandResponder() {  

     public synchronized void processPdu(CommandResponderEvent e) {  

       PDU command = e.getPDU();  

       if (command != null) {  

         System.out.println(command.toString());  

       }  

     }  

   };  

   snmp.addCommandResponder(trapPrinter);  

Version:   

1.8   

Author:   

Frank Fock  

translate:avery_leo 

// add user to the USM

   snmp.getUSM().addUser(new OctetString("MD5DES"),

                         new UsmUser(new OctetString("MD5DES"),

                                     AuthMD5.ID,

                                     new OctetString("MD5DESUserAuthPassword"),

                                     PrivDES.ID,

                                     new OctetString("MD5DESUserPrivPassword")));

   // create the target

   UserTarget target = new UserTarget();

   target.setAddress(targetAddress);

   target.setRetries(1);

   target.setTimeout(5000);

   target.setVersion(SnmpConstants.version3);

   target.setSecurityLevel(SecurityLevel.AUTH_PRIV);

   target.setSecurityName(new OctetString("MD5DES"));

   // create the PDU

   PDU pdu = new ScopedPDU();

   pdu.add(new VariableBinding(new OID("1.3.6")));

   pdu.setType(PDU.GETNEXT);

   // send the PDU

   ResponseEvent response = snmp.send(pdu, target);

   // extract the response PDU (could be null if timed out)

   PDU responsePDU = response.getResponse();

   // extract the address used by the agent to send the response:

   Address peerAddress = response.getPeerAddress();

 An asynchronous SNMPv1 request is sent by the following code:

   // setting up target

   CommunityTarget target = new CommunityTarget();

   target.setCommunity(new OctetString("public"));

   target.setAddress(targetAddress);

   target.setRetries(2);

   target.setTimeout(1500);

   target.setVersion(SnmpConstants.version1);

   // creating PDU

   PDU pdu = new PDU();

   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,1})));

   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,2})));

   pdu.setType(PDU.GETNEXT);

   // sending request

   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);

       System.out.println("Received response PDU is: "+event.getResponse());

     }

   };

   snmp.sendPDU(pdu, target, null, listener);

//Traps (notifications) and other SNMP PDUs can be received by adding the folling code to the first code snippet above:

   CommandResponder trapPrinter = new CommandResponder() {

     public synchronized void processPdu(CommandResponderEvent e) {

       PDU command = e.getPDU();

       if (command != null) {

         System.out.println(command.toString());

       }

     }

   };

   snmp.addCommandResponder(trapPrinter);

Version:

1.8

Author:

Frank Fock

translate:avery_leo

Snmp類提供了一套有關Snmp的功能接口。具體來講,就是發送、接受、建立Snmp消息。

    一個Snmp對象是一個Session,而在Snmp4j中,一個Session可以同多個遠端裝置通信。

(1) Snmp、Target、PDU三者的關系

    Target代表遠端裝置或者遠端實體、PDU代表管理端同Target通信的資料,Snmp就代表管理者管理功能(其實就是資料的收發)的具體執行者。

       打個比方:Target就是你遠方的戀人,PDU就是你們之間傳遞的情書、而Snmp就是負責幫你寄信收信的郵差。

(2)Snmp收發資料的兩種方式

    Snmp可以同步、也可異步收發資料。詳細見代碼示例說明。

(3)Snmp與傳輸層協定

    Snmp可以定制傳輸層協定,一般選擇udp,也可以選擇tcp。詳細見代碼示例說明。

(4)Snmp與Usm

    建立Snmp用來發送Snmpv3版本的消息時候,一般還要建立USM,将它添加至安全模型管理器(SecriryModels)中,同時還需要向Usm 中添加相應的USM使用者(UsmUser)。詳細見代碼示例說明。

代碼示例:(摘自Snmp4j的API文檔)

(1)建立Snmp

    1)使用UDP傳輸協定

TransportMapping transport = new DefaultUdpTransportMapping();

   snmp = new Snmp(transport);     2)使用TCP傳輸協定

TransportMapping transport = new DefaultTcpTransportMapping();

   snmp = new Snmp(transport);    3)建立用于Snmpv3的Snmp

// 建立Snmp

   TransportMapping transport =

      new DefaultUdpTransportMapping();

   Snmp snmp = new Snmp(transport);

   if (version == SnmpConstants.version3) {

       byte[] localEngineID =

            ((MPv3)snmp.getMessageProcessingModel(MessageProcessingModel.MPv3)).createLocalEngineID();

       // 建立USM

       USM usm = new USM(SecurityProtocols.getInstance(),

                      new OctetString(localEngineID), 0);

       // 将USM添加至安全模式管理器中

       // 安全模型管理器采用了單例模式,它内部可以維護為3個安全模型,分别對應Snmp三個版本

       SecurityModels.getInstance().addSecurityModel(usm);

       snmp.setLocalEngine(localEngineID, 0, 0);

       // 添加使用者

       snmp.getUSM().addUser(securityName,new UsmUser(securityName,authProtocol,

                            authPassphrase,privProtocol,privPassphrase));

     }(2)同步收發消息

import org.snmp4j.*;

    ...

    Snmp snmp = new Snmp(new DefaultUdpTransportMapping());

    ...

    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());

    }(3)異步收發消息

import org.snmp4j.*;

    import org.snmp4j.event.*;

    ...

    Snmp snmp = new Snmp(new DefaultUdpTransportMapping());

    ...

    // 增加監聽器

    ResponseListener listener = new ResponseListener() {

       public void onResponse(ResponseEvent event) {

            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);

     ...(4)實作trap

       實作trap需要三步:

       1)建立Snmp;

       2)對于listen()使處于網絡監聽(實際上是同于網絡程式設計中的Socket監聽);

       3)實作CommandResponder接口的監聽器,并且調用 Snmp.addCommandResponder(CommandResponder)注冊監聽器。

import org.snmp4j.*;

    import org.snmp4j.smi.*;

    import org.snmp4j.mp.SnmpConstants;

    ...

    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);

    transport.listen();

    ...

    // 實作CommandResponder接口

    public synchronized void processPdu(CommandResponderEvent e) {

        PDU command = e.getPdu();

        if (command != null) {

        ...

       }

    }

總結

    Snmp内含了一個消息分發器,消息分發器中内含了處理網絡的線程,在使用完後最好調用close(),将其資源回歸處理。

    掌握了上面所說的三個概念,基本上可以使用Snmp4j編寫Snmp的程式了。  

    有關Snmp4j程式設計最好也最詳細的資料:API文檔和源代碼。關于使用Snmp4j編寫Snmp程式的例子,多線程的例子可以參看源代碼 中:org.snmp4j.test包下的MultiThreadedTrapReceiver.java,完整的例子可以參看 org.snmp4j.tools.console包下的SnmpRequest(一個指令行的Snmp管理器)。

    不過,要想快速和深入掌握Snmp程式設計,最好的辦法一定是先弄懂Snmp協定,這方面的資料最權威的就是RFC協定了。