2012-03-08 64 views
3

我在Java中有一個SNMP陷阱應用程序,旨在偵聽SNMP代理並在JFrame窗口的JTextArea上打印接收到的SNMP消息。Java SNMP4J陷阱應用程序正在凍結GUI

下面的第I部分是我的源代碼,顯示了類TrapReceiver的內容。在這堂課中,傾聽法是充分利用這個工作的地方。該類在我想在所提及的JTeaxtArea上顯示消息的JFrame類中進行了插入。我將JTextArea對象的引用,SNMP代理URL和端口發送到類TrapReceiver的構造函數中,然後調用TrapReceiver對象的run方法以在JFrame實例以外的單獨線程中啓動執行。下面的第二部分展示了我如何在JFrame實例中實例化TrapReceiver類。

當我運行應用程序時,我注意到JFrame實例(即GUI)凍結,並且沒有消息正在JFrame實例內的所謂JTeaxtArea上打印,實例化了下面第I部分中所示的類TrapRececeiver。

我的問題是爲什麼JFrame實例(即GUI)凍結,儘管TRapReceiver本身作爲單獨的線程執行?另外,我想知道這個凍結問題的可能解決方案是什麼。提前致謝。

P.S .:我已經驗證TrapReceiver工作正常,並且可以在沒有GUI的情況下作爲獨立應用程序運行時將消息打印到標準輸出,但由於某些可能的線程同步問題,它會以某種方式凍結。我試圖運行TrapReceiver而不把它放到線程中,即使在這種情況下,GUI仍然凍結。

PART我

package com.[Intenionally removed].snmp; 

import java.io.IOException; 
import javax.swing.JTextArea; 
import org.snmp4j.*; 
import org.snmp4j.mp.MPv1; 
import org.snmp4j.mp.MPv2c; 
import org.snmp4j.security.Priv3DES; 
import org.snmp4j.security.SecurityProtocols; 
import org.snmp4j.smi.OctetString; 
import org.snmp4j.smi.TcpAddress; 
import org.snmp4j.smi.TransportIpAddress; 
import org.snmp4j.smi.UdpAddress; 
import org.snmp4j.transport.AbstractTransportMapping; 
import org.snmp4j.transport.DefaultTcpTransportMapping; 
import org.snmp4j.transport.DefaultUdpTransportMapping; 
import org.snmp4j.util.MultiThreadedMessageDispatcher; 
import org.snmp4j.util.ThreadPool; 

public class TrapReceiver implements CommandResponder, Runnable { 

    private String targetSnmpAgentURL; 
    private int targetSnmpAgentPort; 
    private JTextArea outConsole; 

    public TrapReceiver() { 
    } 

    public TrapReceiver(JTextArea outConsole) { 
     this.outConsole = outConsole; 
    } 


    public TrapReceiver(JTextArea outConsole, String targetSnmpAgentURL, int targetSnmpAgentPort) { 
     this.targetSnmpAgentURL = targetSnmpAgentURL; 
     this.targetSnmpAgentPort = targetSnmpAgentPort; 
     this.outConsole = outConsole; 

     try { 
      listen(new UdpAddress(targetSnmpAgentURL + "/" + targetSnmpAgentPort)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public final synchronized void listen(TransportIpAddress address) throws IOException { 


     AbstractTransportMapping transport; 
     if (address instanceof TcpAddress) { 
      transport = new DefaultTcpTransportMapping((TcpAddress) address); 
     } else { 
      transport = new DefaultUdpTransportMapping((UdpAddress) address); 
     } 

     ThreadPool threadPool = ThreadPool.create("DispatcherPool", 10); 
     MessageDispatcher mDispathcher = new MultiThreadedMessageDispatcher(
      threadPool, new MessageDispatcherImpl()); 

     // add message processing models 
     mDispathcher.addMessageProcessingModel(new MPv1()); 
     mDispathcher.addMessageProcessingModel(new MPv2c()); 

     // add all security protocols 
     SecurityProtocols.getInstance().addDefaultProtocols(); 
     SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES()); 

     // Create Target 
     CommunityTarget target = new CommunityTarget(); 
     target.setCommunity(new OctetString("public")); 

     Snmp snmp = new Snmp(mDispathcher, transport); 
     snmp.addCommandResponder(this); 

     transport.listen(); 
     System.out.println("Listening on " + address); 

     try { 
      this.wait(); 
     } catch (InterruptedException ex) { 
      Thread.currentThread().interrupt(); 
     } 
     } 

    /** 
    * This method will be called whenever a pdu is received on the given port 
    * specified in the listen() method 
    */ 
    @Override 
    public synchronized void processPdu(CommandResponderEvent cmdRespEvent) { 
     //System.out.println("Received PDU..."); 
     outConsole.append("Received PDU...\n"); 
     PDU pdu = cmdRespEvent.getPDU(); 

     if (pdu != null) {    
     outConsole.append("Trap Type = " + pdu.getType() + "\n"); 
     outConsole.append("Alarm Type: " + pdu.getVariableBindings().get(4) + "\n"); 
     outConsole.append("Alarm Message: " + pdu.getVariableBindings().get(9) + "\n\n"); 

     } 
    } 


    @Override 
    public void run() { 
     try {   
      listen(new UdpAddress(targetSnmpAgentURL + "/" + targetSnmpAgentPort)); 
     } catch (IOException e) { 
      outConsole.append("\nError occured while listening to SNMP messages: \n" + e.getMessage() + "\n\n"); 
     } 
    } 

} //end of class TrapReceiver 

PART II

在下面,我在一個線程中運行類的TrapReceiver的一個實例。

private void jButtonStartListeningSNMPActionPerformed(java.awt.event.ActionEvent evt) {               

    Thread snmpThread = 
      new Thread(new TrapReceiver(jTextAreaSNMPAlarmOutput, jTextFieldSnmpAgentUrl.getText().trim(), Integer.parseInt(jTextFieldSnmpAgentPort.getText().trim()))); 
    snmpThread.start() 

    } 

回答

5

的問題是,你是在TrapReceiver構造函數,它發生在GUI線程上調用listen()。您只需要在run()方法中調用listen(),因爲這是新線程中發生的部分。

+0

似乎我忘了刪除它。我剛剛完成了它,但GUI仍然凍結。根據java教程(位於http://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html),「因爲所有的繪圖和事件監聽方法都在同一個線程中執行,所以緩慢的事件 - 監聽器方法可能會使程序看起來沒有反應,並且重新繪製速度很慢,如果需要通過事件執行一些冗長的操作,可以通過啓動另一個線程來完成。 這,我已經在做我的applcation,但我不明白爲什麼它不起作用。 – 2012-03-08 13:33:43

+2

嘿,我解決了這個問題。我發送線程對象java.awt.inVokeLater方法,但它看起來只有一個事件調度線程(根據我從Java教程讀取)。所以,你的建議幫助忘記了在constrcutor中刪除電話是我的錯誤。總之,上文第二部分的調用是正確的做法。謝謝。 – 2012-03-08 13:39:09

+1

對不起太多複製粘貼露出了我的頭腦雲,但如果有人需要上面的snmp陷阱是工作代碼:) – 2012-03-08 13:40:09