Приложение Java SNMP4J Trap замораживает графический интерфейс

У меня есть приложение-ловушка SNMP на Java, которое предназначено для прослушивания агента SNMP и печати полученных сообщений SNMP в JTextArea в окне JFrame.

Часть I ниже — мой исходный код, показывающий содержимое класса TrapReceiver. В этом классе метод listen выполняет большую часть работы. Класс создан внутри класса JFrame, в котором я намерен отображать сообщения в упомянутой JTeaxtArea. Я отправляю ссылку на объект JTextArea, URL-адрес агента SNMP и порт в конструктор класса TrapReceiver, а затем вызываю метод запуска объекта TrapReceiver, чтобы начать выполнение в отдельном потоке, отличном от экземпляра JFrame. Часть II ниже показывает, как я создаю экземпляр класса TrapReeceiver в экземпляре JFrame.

Когда я запускаю приложение, я заметил, что экземпляр JFrame (т. е. GUI) зависает, и никакое сообщение не печатается в упомянутом JTeaxtArea внутри экземпляра JFrame, который создает экземпляр класса TrapReeceiver, показанный в части I ниже.

Мой вопрос: почему экземпляр JFrame (т.е. GUI) зависает, хотя сам TRapReceiver выполняется как отдельный поток? Кроме того, мне интересно, что может быть возможным решением этой проблемы с зависанием. Заранее спасибо.

P.S.: Я убедился, что TrapReceiver работает нормально и может выводить сообщения на стандартный вывод при работе в качестве автономного приложения без графического интерфейса, но именно этот графический интерфейс каким-то образом зависает из-за какой-то возможной проблемы с синхронизацией потоков. Я попытался запустить TrapReceiver без включения потока, и даже в этом случае графический интерфейс все еще зависал.

ЧАСТЬ I

 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

ЧАСТЬ 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()

   }

person F. Aydemir    schedule 08.03.2012    source источник


Ответы (1)


проблема в том, что вы вызываете listen() в конструкторе TrapReceiver, что происходит в потоке графического интерфейса. вы хотите вызвать только listen() в методе run(), так как это часть, которая происходит в новом потоке.

person jtahlborn    schedule 08.03.2012
comment
Кажется, я забыл его удалить. Я сделал это только что, но графический интерфейс все еще зависает. Согласно учебнику по Java (по адресу docs.oracle.com/javase/tutorial /uiswing/events/), поскольку все методы рисования и прослушивания событий выполняются в одном потоке, медленный метод прослушивания событий может привести к тому, что программа не будет отвечать на запросы и медленно перерисовывать себя. Если вам нужно выполнить какую-то длительную операцию в результате события, сделайте это, запустив другой поток. Это я уже делаю в своем приложении, но не понимаю, почему это не работает. - person F. Aydemir; 08.03.2012
comment
Эй, я решил проблему. Я отправлял объект потока методу java.awt.inVokeLater, но похоже, что может быть только один поток диспетчеризации событий (согласно тому, что я прочитал из учебника по Java). Итак, ваше предложение помогло, это была моя ошибка, я забыл удалить вызов в конструкторе. В заключение, вызов в Части II выше является правильным способом сделать это. Спасибо. - person F. Aydemir; 08.03.2012
comment
Извините, что слишком много копировальной пасты заставило меня задуматься над облаками, но если кому-то нужна ловушка snmp, приведенная выше, это рабочий код :) - person F. Aydemir; 08.03.2012