java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java内部网段扫描

基于Java编写一个简单的内部网段扫描程序

作者:mycqyjn

这篇文章主要为大家详细介绍了如何基于Java编写一个简单的内部网段扫描程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解下

说明

这段代码实现了一个简单的内部网段扫描工具,基于 Java Swing 构建图形用户界面(GUI),并使用多线程来扫描本地网段中的活跃主机。涉及内容包括:

代码解读

功能概述

1.界面设计:

2.扫描逻辑:

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/24\n");
                    });
                    ExecutorService executor = Executors.newFixedThreadPool(20);//建立线程池
                    for (int i = 1; i <= 254; i++) {//逐个扫描本地网段
                        String ip = netSegment + i;
                        executor.execute(new ScanerIp(ip));
                    }
                    executor.shutdown();//关闭线程池
                    boolean finished = executor.awaitTermination(2, TimeUnit.MINUTES);//检查线程是否超时
                    SwingUtilities.invokeLater(() -> {//更新文本域
                        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/24\n");
                    });
                    ExecutorService executor = Executors.newFixedThreadPool(20);//建立线程池
                    for (int i = 1; i <= 254; i++) {//逐个扫描本地网段
                        String ip = netSegment + i;                        
                        executor.execute(new ScanerIp(ip));
                    }
                    executor.shutdown();//关闭线程池
                    boolean finished = executor.awaitTermination(2, TimeUnit.MINUTES);//检查线程是否超时
                    SwingUtilities.invokeLater(() -> {//更新文本域
                        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内部网段扫描内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文