我在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()
}
似乎我忘了刪除它。我剛剛完成了它,但GUI仍然凍結。根據java教程(位於http://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html),「因爲所有的繪圖和事件監聽方法都在同一個線程中執行,所以緩慢的事件 - 監聽器方法可能會使程序看起來沒有反應,並且重新繪製速度很慢,如果需要通過事件執行一些冗長的操作,可以通過啓動另一個線程來完成。 這,我已經在做我的applcation,但我不明白爲什麼它不起作用。 – 2012-03-08 13:33:43
嘿,我解決了這個問題。我發送線程對象java.awt.inVokeLater方法,但它看起來只有一個事件調度線程(根據我從Java教程讀取)。所以,你的建議幫助忘記了在constrcutor中刪除電話是我的錯誤。總之,上文第二部分的調用是正確的做法。謝謝。 – 2012-03-08 13:39:09
對不起太多複製粘貼露出了我的頭腦雲,但如果有人需要上面的snmp陷阱是工作代碼:) – 2012-03-08 13:40:09