我已经使用java创建了一个portscanner,但是当我点击执行它时就冻结了

0 java for-loop freeze port-scanning

下面的代码是我用来创建端口扫描程序的,但是,当我点击"扫描"它执行但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");
    }

}
}
Run Code Online (Sandbox Code Playgroud)

这个顶部代码是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)
        {

        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

Hov*_*els 5

这是在Swing事件线程(EDT或事件调度线程)中执行长时间运行的过程的典型示例,因此冻结此线程使GUI无法运行.我们看到这种事情一次又一次地发布,并且解决方案是相同的并且相对简单:在后台线程中执行长时间运行的进程,例如可以由SwingWorker提供.有关这方面的更多信息,请阅读Swing中的Concurrency,或者在此站点上搜索类似的问题,因为它再次讨论了很多.

关于你的代码的另一点,永远不要这样做:

    catch(IOException e)
    {

    }
Run Code Online (Sandbox Code Playgroud)

如果你忽略了异常,你实际上是盲目的.至少,打印堆栈跟踪,即:

    catch(IOException e)
    {
       e.printStackTrace();
    }
Run Code Online (Sandbox Code Playgroud)

同样在这里:

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

我自己,我在PortScanner构造函数中设置了PortScanner对象,但是会在一个单独的公共方法中运行扫描,比如调用scan().这将允许我在事件线程上设置PortScanner对象,然后通过调用其scan()方法在后台线程中扫描它.有时这更方便.

编辑
我还给PortScanner类添加了一个PropertyChangeListener,以便它可以允许其他类监听它的更改,包括有关端口的信息.这样,您可以在GUI中发布PortScanner端口信息.最简单的方法是让你的PortScanner对象扩展SwingWorker,因为SwingWorkers内置了PropertyChangeSupport.然后你可以使用发布/进程方法对将端口信息发布到GUI而不是在println语句中打印出来.我上面链接的教程描述了如何执行此操作,如果您遇到困难,我们可以帮助您了解详细信息.