欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

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

来源: javaer 分享于  点击 584 次 点评:199

基于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内部网段扫描内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

      您可能感兴趣的文章:
      • python实现扫描局域网指定网段ip的方法
      • C#中实现网段扫描的代码
      • java判断ip是否为指定网段示例
      • java IP地址网段计算的示例代码
      相关栏目:

      用户点评