我在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