0

以下のコードは、ポートスキャナーを作成するために使用しているものですが、「スキャン」をクリックすると実行されますが、スキャンが完了するまで GUI がフリーズします。スキャン中に他のアクションを実行できるようにする方法はありますか?

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class PortScannerGUI extends JFrame implements ActionListener
{
JPanel Panel = new JPanel(null);
JTextField Field = new JTextField();
JButton Button = new JButton();
JTextArea Area = new JTextArea();
JButton limit = new JButton("limit");

public PortScannerGUI()
{
    super();
    setSize(350, 400);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setResizable(false);
    setLocationRelativeTo(null);
    LoadUI();
}

public void LoadUI()
{
    Area.setBounds(20, 50, 310, 310);
    Area.setBorder(BorderFactory.createLineBorder(Color.BLUE));
    Area.setEditable(false);

    Field.setBounds(20, 10, 200, 35);

    Button.setBounds(230, 10,100, 35);
    Button.setText("Scan");
    Button.addActionListener(this);

    Panel.add(Field);
    Panel.add(Area);
    Panel.add(Button);
    add(Panel);
    setVisible(true);
}

public static void main(String[] args)
{
    PortScannerGUI Main = new PortScannerGUI();
}

@Override
public void actionPerformed(ActionEvent arg0)
{
    Thread Runner = new Thread();
    Runner.start();
    int j=0;
    String str = Field.getText();
    for(int i=1;i<str.length();i++)
    {
        if(str.substring(i-1, i).equals("."))
        {
            j++;
        }
    }
    if(!str.equals("") || j==4 || j==6)
    {
        try
        {
            InetAddress IP = InetAddress.getByName(str);
            PortScanner P = new PortScanner(IP);
        }
        catch (Exception e){}
    }
    else
    {
        JOptionPane.showMessageDialog(null, "Not an IP address");
    }

}
}

この上部のコードは GUI 部分のコードで、以下は実際にポートをスキャンするコードです。

import java.io.IOException;

import java.net.InetAddress;

import java.net.Socket;

public class PortScanner
{
public PortScanner(InetAddress iA)
{
    for (int port = 1; port <= 65535; port++)
    {
        try
        {
            Socket s = new Socket(iA, port);
            System.out.println("Port " + port + " is open");
            s.close();
        }
        catch(IOException e)
        {

        }
    }
}
}
4

1 に答える 1

5

これは、Swing イベント スレッド (EDT またはイベント ディスパッチ スレッド) で実行時間の長いプロセスを実行し、このスレッドをフリーズして GUI を機能させない典型的な例です。この種の投稿が何度も見られますが、解決策は同じで比較的単純です。SwingWorker によって提供されるようなバックグラウンド スレッドで長時間実行されるプロセスを実行します。詳細については、 Swingでの同時実行 を参照するか、このサイトで同様の問題を検索してください。

あなたのコードに関するもう一つのポイントは、決してこれをしないでください:

    catch(IOException e)
    {

    }

例外を無視すると、文字通り盲目的に飛ぶことになります。少なくとも、スタック トレースを出力します。

    catch(IOException e)
    {
       e.printStackTrace();
    }

ここでも同じ:

     try {
        InetAddress IP = InetAddress.getByName(str);
        PortScanner P = new PortScanner(IP);
     } catch (Exception e) {
        e.printStackTrace();  // **** add this!
     }

私自身、PortScanner コンストラクターで PortScanner オブジェクトをセットアップしましたが、スキャンは別のパブリック メソッドで実行し、scan(). これにより、イベント スレッドで PortScanner オブジェクトをセットアップし、そのscan()メソッドを呼び出してバックグラウンド スレッドでスキャンすることができます。場合によっては、この方が便利です。

編集
また、PortScanner クラスに PropertyChangeListener を追加できるようにして、他のクラスがポートに関する情報を含む変更をリッスンできるようにします。このようにして、PortScanner ポート情報を GUI で公開できます。これを行う最も簡単な方法は、PortScanner オブジェクトに SwingWorker を拡張させることです。これは、SwingWorkers には PropertyChangeSupport が組み込まれているためです。次に、publish/process メソッドのペアを使用して、ポート情報を println ステートメントで出力するのではなく、GUI に公開できます。上記のリンク先のチュートリアルでは、これを行う方法について説明しています。行き詰まった場合は、詳細をサポートできます。

于 2012-08-04T14:43:52.163 に答える