下面的代码是我用来创建端口扫描程序的代码,但是,当我单击“扫描”时,它会执行,但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)
{
}
}
}
}
最佳答案
这是在Swing事件线程(EDT或事件调度线程)中执行长时间运行的过程,并因此冻结该线程而导致GUI无法运行的经典示例。我们一次又一次看到这种事情,解决方案是相同且相对简单的:在后台线程中进行长时间运行的过程(例如SwingWorker可以提供的)。有关更多信息,请阅读Concurrency in 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,以便它可以允许其他类侦听它的更改,包括端口信息。这样,您可以在GUI中发布PortScanner端口信息。最简单的方法是让PortScanner对象扩展SwingWorker,因为SwingWorkers内置了PropertyChangeSupport。然后,您可以使用publish / process方法对将端口信息发布到GUI,而不是在println语句中打印出来。我上面链接的教程描述了如何执行此操作,如果您遇到困难,我们可以为您提供详细信息。