Snmp4j編程簡介之三:Snmp


All Implemented Interfaces:
java.util.EventListener, CommandResponderSession

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

 

    Snmp採用獨立的傳輸協議,通過TransportMapping 接口調用addTransportMapping(TransportMapping transportMapping) 方法或者採用默認的構造函數來實現傳輸映射,以此來實現信息的傳輸。

 

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

 

  1. Address targetAddress = GenericAddress.parse("udp:127.0.0.1/161");   
  2.    TransportMapping transport = new DefaultUdpTransportMapping();   
  3.    snmp = new Snmp(transport);   
  4.    USM usm = new USM(SecurityProtocols.getInstance(),   
  5.                      new OctetString(MPv3.createLocalEngineID()), 0);   
  6.    SecurityModels.getInstance().addSecurityModel(usm);   
  7.    transport.listen();  
如何實現SNMPv3信息的同步發送,下面舉例說明:
 
  1. // add user to the USM   
  2.    snmp.getUSM().addUser(new OctetString("MD5DES"),   
  3.                          new UsmUser(new OctetString("MD5DES"),   
  4.                                      AuthMD5.ID,   
  5.                                      new OctetString("MD5DESUserAuthPassword"),   
  6.                                      PrivDES.ID,   
  7.                                      new OctetString("MD5DESUserPrivPassword")));   
  8.    // create the target   
  9.    UserTarget target = new UserTarget();   
  10.    target.setAddress(targetAddress);   
  11.    target.setRetries(1);   
  12.    target.setTimeout(5000);   
  13.    target.setVersion(SnmpConstants.version3);   
  14.    target.setSecurityLevel(SecurityLevel.AUTH_PRIV);   
  15.    target.setSecurityName(new OctetString("MD5DES"));   
  16.   
  17.    // create the PDU   
  18.    PDU pdu = new ScopedPDU();   
  19.    pdu.add(new VariableBinding(new OID("1.3.6")));   
  20.    pdu.setType(PDU.GETNEXT);   
  21.   
  22.    // send the PDU   
  23.    ResponseEvent response = snmp.send(pdu, target);   
  24.    // extract the response PDU (could be null if timed out)   
  25.    PDU responsePDU = response.getResponse();   
  26.    // extract the address used by the agent to send the response:   
  27.    Address peerAddress = response.getPeerAddress();   
  28.  An asynchronous SNMPv1 request is sent by the following code:    
  29.   
  30.    // setting up target   
  31.    CommunityTarget target = new CommunityTarget();   
  32.    target.setCommunity(new OctetString("public"));   
  33.    target.setAddress(targetAddress);   
  34.    target.setRetries(2);   
  35.    target.setTimeout(1500);   
  36.    target.setVersion(SnmpConstants.version1);   
  37.    // creating PDU   
  38.    PDU pdu = new PDU();   
  39.    pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,1})));   
  40.    pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,2})));   
  41.    pdu.setType(PDU.GETNEXT);   
  42.    // sending request   
  43.    ResponseListener listener = new ResponseListener() {   
  44.      public void onResponse(ResponseEvent event) {   
  45.        // Always cancel async request when response has been received   
  46.        // otherwise a memory leak is created! Not canceling a request   
  47.        // immediately can be useful when sending a request to a broadcast   
  48.        // address.   
  49.        ((Snmp)event.getSource()).cancel(event.getRequest(), this);   
  50.        System.out.println("Received response PDU is: "+event.getResponse());   
  51.      }   
  52.    };   
  53.    snmp.sendPDU(pdu, target, null, listener);   
  54.     
  55. //Traps (notifications) and other SNMP PDUs can be received by adding the folling code to the first code snippet above:    
  56.    CommandResponder trapPrinter = new CommandResponder() {   
  57.      public synchronized void processPdu(CommandResponderEvent e) {   
  58.        PDU command = e.getPDU();   
  59.        if (command != null) {   
  60.          System.out.println(command.toString());   
  61.        }   
  62.      }   
  63.    };   
  64.    snmp.addCommandResponder(trapPrinter);   
  65.     
  66.   
  67.   
  68. Version:    
  69. 1.8    
  70. Author:    
  71. Frank Fock   
  72. 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協議了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章