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

 更新时间:2025年02月11日 09:42:09   作者:mycqyjn  
这篇文章主要为大家详细介绍了如何基于Java编写一个简单的内部网段扫描程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解下

说明

这段代码实现了一个简单的内部网段扫描工具,基于 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/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内部网段扫描内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot集成Redis之配置、序列化与持久化方式

    SpringBoot集成Redis之配置、序列化与持久化方式

    本文介绍了Redis的基本概念、常用数据类型及操作、SpringBoot整合Redis的方法、高级特性与安全性、性能优化、测试与部署、数据一致性及版本更新等内容,通过本文的学习,读者可以掌握Redis的使用方法,并在实际项目中发挥其优势
    2024-11-11
  • Java Scanner对象中hasNext()与next()方法的使用

    Java Scanner对象中hasNext()与next()方法的使用

    这篇文章主要介绍了Java Scanner对象中hasNext()与next()方法的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java插入JSON对象到PostgreSQL的步骤详解

    Java插入JSON对象到PostgreSQL的步骤详解

    在现代软件开发中,由于 JSON 数据的轻量和通用性,处理 JSON 数据已经变得无处不在,PostgreSQL 凭借其对 JSON 的强大支持,为存储和查询 JSON 数据提供了出色的平台,本文给大家介绍了Java插入JSON对象到PostgreSQL的步骤,需要的朋友可以参考下
    2024-11-11
  • Mybatis中的常用OGNL表达式

    Mybatis中的常用OGNL表达式

    这篇文章主要介绍了Mybatis中的常用OGNL表达式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • SpringAOP中的Advisor详解

    SpringAOP中的Advisor详解

    这篇文章主要介绍了SpringAOP中的Advisor详解,平时我们项目中涉及到 AOP,基本上就是声明式配置一下就行了,无论是基于 XML 的配置还是基于 Java 代码的配置,都是简单配置即可使用,今天就来看一下声明式配置的使用,需要的朋友可以参考下
    2023-08-08
  • springboot如何使用logback-spring配置日志格式,并分环境配置

    springboot如何使用logback-spring配置日志格式,并分环境配置

    这篇文章主要介绍了springboot如何使用logback-spring配置日志格式,并分环境配置的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • MyBatis通过JDBC数据驱动生成的执行语句问题

    MyBatis通过JDBC数据驱动生成的执行语句问题

    这篇文章主要介绍了MyBatis通过JDBC数据驱动生成的执行语句问题的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-08-08
  • mybatis如何处理返回结果集

    mybatis如何处理返回结果集

    这篇文章主要介绍了mybatis如何处理返回结果集问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java初始化块及执行过程解析

    Java初始化块及执行过程解析

    这篇文章主要介绍了Java初始化块及执行过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java 使用Thumbnails对大图片压缩

    Java 使用Thumbnails对大图片压缩

    这篇文章主要介绍了Java 使用Thumbnails对大图片压缩,帮助大家更好的利用Java处理图片,感兴趣的朋友可以了解下
    2020-11-11

最新评论