我有一个 Java 中的 SNMP 陷阱应用程序,旨在侦听 SNMP 代理并在 JFrame 窗口中的 JTextArea 上打印收到的 SNMP 消息。
下面的第一部分是我的源代码,显示了类 TrapReceiver 的内容。在这个类中,listen 方法是最能发挥作用的地方。该类在一个 JFrame 类中被实例化,我打算在上面提到的 JTeaxtArea 上显示消息。我将 JTextArea 对象的引用、SNMP 代理 URL 和端口发送到类 TrapReceiver 的构造函数中,然后调用 TrapReceiver 对象的 run 方法以在 JFrame 实例之外的单独线程中开始执行。下面的第二部分显示了我如何在 JFrame 实例中实例化类 TrapReeceiver。
当我运行该应用程序时,我注意到 JFrame 实例(即 GUI)正在冻结,并且没有在 JFrame 实例中所提到的 JTeaxtArea 上打印任何消息,该实例实例化了下面第一部分中显示的类 TrapReeceiver。
我的问题是尽管 TRapReceiver 本身作为单独的线程执行,但为什么 JFrame 实例(即 GUI)会冻结?另外,我想知道这个冻结问题的可能解决方案是什么。提前致谢。
PS:我已经验证 TrapReceiver 工作正常,并且可以在作为没有 GUI 的独立应用程序运行时将消息打印到标准输出,但是由于某些可能的线程同步问题,这个 GUI 以某种方式冻结。我尝试在不使用线程的情况下运行 TrapReceiver,即使在这种情况下,GUI 仍然冻结。
第一部分
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
第二部分
下面,我在一个线程中运行 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()
}