说明
这段代码实现了一个简单的内部网段扫描工具,基于 Java Swing 构建图形用户界面(GUI),并使用多线程来扫描本地网段中的活跃主机。涉及内容包括:
- 图形用户界面:按键及监听、文本域、滚动条容器、安全更新文本域内容等;
- 简单的跨平台方法;
- 简单的线程池应用方法;
代码解读
功能概述
1.界面设计:
- 程序包含一个文本域(JTextArea)用于显示扫描结果。
- 有两个按钮:一个用于开始扫描,另一个用于退出程序。
2.扫描逻辑:
- 程序通过 ping 命令检测本地网段中的活跃主机。
- 使用多线程(线程池)并发执行扫描任务,提高扫描效率。
- 扫描完成后,结果显示在文本域中。
3.跨平台支持:
根据操作系统(Windows 或其他系统)调整 ping 命令的格式。
代码分解
界面部分
Container conn = getContentPane();//定义窗体容器
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认窗体关闭
setBounds(300, 300, 400, 300);//设置窗体初始位置及大小
setTitle("内部网段扫描");//设置窗体标题
JScrollPane jScrollPane = new JScrollPane();//实例化滚动条容器
conn.add(jScrollPane, BorderLayout.CENTER);//向窗体容器中添加滚动条容器
scanner = new JTextArea();//实例化文本域
jScrollPane.setViewportView(scanner);//添加文本域对象到滚动条容器
JPanel jPanel = new JPanel();//实例化布局
conn.add(jPanel, BorderLayout.SOUTH);//将布局添加到窗体容器底部
startButt = new JButton("开始扫描...");//实例化开始扫描按键
jPanel.add(startButt);//将开始按键添加到布局
closeButt = new JButton("退 出");//实例化退出按键
jPanel.add(closeButt);//将退出按键添加到布局
其中:
实现扫描结果回显到图形界面
scanner = new JTextArea();//实例化文本域
jScrollPane.setViewportView(scanner);//添加文本域对象到滚动条容器
定义界面按键用以完成用户交互
startButt = new JButton("开始扫描...");//实例化开始扫描按键
jPanel.add(startButt);//将开始按键添加到布局
closeButt = new JButton("退 出");//实例化退出按键
jPanel.add(closeButt);//将退出按键添加到布局
功能部分
获取本地网段
private String localIP() throws UnknownHostException {
InetAddress host = InetAddress.getLocalHost();//获取本机网络信息
String hostAddress = host.getHostAddress();//获取本机ip地址
if (hostAddress == null) {//判断本机是否联网
return "网段获取错误";
}
int pos = hostAddress.lastIndexOf(".");//指针移动到网段最后一个.上
return hostAddress.substring(0, pos + 1);//返回本机网段
}
通过 InetAddress.getLocalHost() 获取本机 IP 地址。
提取 IP 地址的网段部分(例如,从 192.168.1.100 提取 192.168.1.)。
生成扫描命令【ping】
private String pingCommand() {
String os = System.getProperty("os.name").toLowerCase();//读取系统平台关键字,并且转换为小写
return os.contains("win") ? "cmd /c ping -n 1 -w 1000 " : "ping -c 1 -W 1 ";//根据系统平台返回不同的ping命令
}
根据操作系统返回不同的 ping 命令格式
网段扫描【内部类】
class ScanerIp implements Runnable {
//定义类私有变量
private final String ip;//定义一个字符串用以存储需要扫描的ip地址
public ScanerIp(String ip) {
this.ip = ip;//初始化ip地址
}
@Override
public void run() {
String command = pingCommand() + ip;//赋值ping命令
boolean isReachable = false;//判断目的主机是否可达
try {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), Charset.defaultCharset()));//创建一个缓存器,用以存储命令结果
StringBuilder output = new StringBuilder();//建立一个命令执行的输出变量
String line;
while ((line = reader.readLine()) != null) {//逐行输出命令结果
output.append(line).append("n");
}
int exitCode = process.waitFor();//创建进程结束退出变量
String os = System.getProperty("os.name").toLowerCase();//获取系统平台信息
boolean isWindows = os.contains("win");//系统平台为win时,变量为true
if (isWindows) {//判断目的主机是否可达
isReachable = output.toString().contains("TTL=");
} else {
isReachable = (exitCode == 0);
}
} catch (Exception ex) {
ex.printStackTrace();
}
if (isReachable) {//目的主机可达时,更新文本域内容
SwingUtilities.invokeLater(() -> scanner.append(ip + "n"));
}
}
}
每个 ScanerIp 实例负责扫描一个 IP 地址。
使用 Runtime.exec 执行 ping 命令,并根据输出判断 IP 是否可达。
如果 IP 可达,通过 SwingUtilities.invokeLater 更新文本域,确保线程安全。
扫描按钮监听
private class StartButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
startButt.setEnabled(false);//设置按键状态为不可用
new Thread(() -> {
try {
String netSegment = localIP();//调用localIP()将本地网段给变量赋值
SwingUtilities.invokeLater(() -> {//更新文本域显示内容
scanner.setText("开始扫描网段: " + netSegment + "0/24n");
});
ExecutorService executor = Executors.newFixedThreadPool(20);//建立线程池
for (int i = 1; i {//更新文本域
scanner.append(finished ? "扫描完成!n" : "扫描超时!n");
startButt.setEnabled(true);//线程完成,按键恢复可用状态
});
} catch (UnknownHostException ex) {
SwingUtilities.invokeLater(() -> {
scanner.append("无法获取本地IP地址: " + ex.getMessage() + "n");
startButt.setEnabled(true);
});
} catch (InterruptedException ex) {
SwingUtilities.invokeLater(() -> {
scanner.append("扫描被中断n");
startButt.setEnabled(true);
});
Thread.currentThread().interrupt();
}
}).start();
}
}
点击“开始扫描”按钮后,程序获取本地网段,并使用线程池并发扫描网段中的每个 IP 地址。
扫描完成后,更新文本域显示扫描结果,并恢复按钮状态。
运行结果

完整代码
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TwentyTwoTestDemo00010002 extends JFrame {
//定义全局变量
private JTextArea scanner;//定义文本域
private JButton startButt;//定义开始扫描按钮
private JButton closeButt;//定义退出按钮
//类构造函数,构造窗体
public TwentyTwoTestDemo00010002() {
Container conn = getContentPane();//定义窗体容器
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认窗体关闭
setBounds(300, 300, 400, 300);//设置窗体初始位置及大小
setTitle("内部网段扫描");//设置窗体标题
JScrollPane jScrollPane = new JScrollPane();//实例化滚动条容器
conn.add(jScrollPane, BorderLayout.CENTER);//向窗体容器中添加滚动条容器
scanner = new JTextArea();//实例化文本域
jScrollPane.setViewportView(scanner);//添加文本域对象到滚动条容器
JPanel jPanel = new JPanel();//实例化布局
conn.add(jPanel, BorderLayout.SOUTH);//将布局添加到窗体容器底部
startButt = new JButton("开始扫描...");//实例化开始扫描按键
jPanel.add(startButt);//将开始按键添加到布局
closeButt = new JButton("退 出");//实例化退出按键
jPanel.add(closeButt);//将退出按键添加到布局
// 添加事件监听
startButt.addActionListener(new StartButtonListener());//添加开始扫描按键监听事件
closeButt.addActionListener(e -> System.exit(0));//添加退出按键退出功能
}
//获取本地网段
private String localIP() throws UnknownHostException {
InetAddress host = InetAddress.getLocalHost();//获取本机网络信息
String hostAddress = host.getHostAddress();//获取本机ip地址
if (hostAddress == null) {//判断本机是否联网
return "网段获取错误";
}
int pos = hostAddress.lastIndexOf(".");//指针移动到网段最后一个.上
return hostAddress.substring(0, pos + 1);//返回本机网段
}
//检测系统平台
private String pingCommand() {
String os = System.getProperty("os.name").toLowerCase();//读取系统平台关键字,并且转换为小写
return os.contains("win") ? "cmd /c ping -n 1 -w 1000 " : "ping -c 1 -W 1 ";//根据系统平台返回不同的ping命令
}
//网段扫描【内部类】
class ScanerIp implements Runnable {
//定义类私有变量
private final String ip;//定义一个字符串用以存储需要扫描的ip地址
public ScanerIp(String ip) {
this.ip = ip;//初始化ip地址
}
@Override
public void run() {
String command = pingCommand() + ip;//赋值ping命令
boolean isReachable = false;//判断目的主机是否可达
try {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), Charset.defaultCharset()));//创建一个缓存器,用以存储命令结果
StringBuilder output = new StringBuilder();//建立一个命令执行的输出变量
String line;
while ((line = reader.readLine()) != null) {//逐行输出命令结果
output.append(line).append("n");
}
int exitCode = process.waitFor();//创建进程结束退出变量
String os = System.getProperty("os.name").toLowerCase();//获取系统平台信息
boolean isWindows = os.contains("win");//系统平台为win时,变量为true
if (isWindows) {//判断目的主机是否可达
isReachable = output.toString().contains("TTL=");
} else {
isReachable = (exitCode == 0);
}
} catch (Exception ex) {
ex.printStackTrace();
}
if (isReachable) {//目的主机可达时,更新文本域内容
SwingUtilities.invokeLater(() -> scanner.append(ip + "n"));
}
}
}
//建立按键监听方法
private class StartButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
startButt.setEnabled(false);//设置按键状态为不可用
new Thread(() -> {
try {
String netSegment = localIP();//调用localIP()将本地网段给变量赋值
SwingUtilities.invokeLater(() -> {//更新文本域显示内容
scanner.setText("开始扫描网段: " + netSegment + "0/24n");
});
ExecutorService executor = Executors.newFixedThreadPool(20);//建立线程池
for (int i = 1; i {//更新文本域
scanner.append(finished ? "扫描完成!n" : "扫描超时!n");
startButt.setEnabled(true);//线程完成,按键恢复可用状态
});
} catch (UnknownHostException ex) {
SwingUtilities.invokeLater(() -> {
scanner.append("无法获取本地IP地址: " + ex.getMessage() + "n");
startButt.setEnabled(true);
});
} catch (InterruptedException ex) {
SwingUtilities.invokeLater(() -> {
scanner.append("扫描被中断n");
startButt.setEnabled(true);
});
Thread.currentThread().interrupt();
}
}).start();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TwentyTwoTestDemo00010002 frame = new TwentyTwoTestDemo00010002();
frame.setVisible(true);
});
}
}
到此这篇关于基于Java编写一个简单的内部网段扫描程序的文章就介绍到这了,更多相关Java内部网段扫描内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!
