今天用Java开发主机IP扫描神器,零基础Socket编程详细

Posted Charzous

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了今天用Java开发主机IP扫描神器,零基础Socket编程详细相关的知识,希望对你有一定的参考价值。

目录

一、开发背景

二、准备工作

三、远程主机 IP 探测

四、核心算法

1、IP地址转化为十进制数

2、十进制数转化为IP地址

五、主机 IP 扫描神器界面

六、各功能代码及IP扫描演示

1、主机扫描按钮

2、停止按钮

3、执行命令按钮

最后


一、开发背景

今天我们来开启一个有趣的实战小项目,运用Java网络编程技术开发一个主机IP扫描探测神器,相信你一定感兴趣,用3个词描述就是简单、好玩、有收获!其实,主机IP扫描就是探测一个IP地址范围内有哪些主机是活动的,是网络攻防的基础和前提。

扫描探测一台目标主机包括的具体信息有:目标主机是否活动、主机的操作系统、正在使用哪些端口、对外提供了哪些服务、相关服务的软件版本等,对这些内容的探测可以为网络攻防提供参考信息。对主机的探测工具非常多,比如功能强大的nmap、netcat、superscan,以及国内的x-scanner等。这次我们自己动手来开发一个主机IP扫描探测小程序,来探测目标主机是否活动,更能加深对网络编程的理解和应用。

二、准备工作

三、远程主机 IP 探测

IP地址的探测就是确定被扫描的IP在网络中开闭状态,因此,开发任务的核心点就在于如何判断IP地址活跃状态。这时可以联想到平常我们使用ping命令来判断目标主机是否可达,ping命令是基于ICMP协议通信的。

由上面分析发现,可以使用Java中的InetAddress类中的isReachable方法进行判断,该方法就是基于ICMP协议判断目标是否可达的。描述如下:

A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.

所以,只需要两行代码就能完成这个探测任务: 

InetAddress  addr = InetAddress.getByName(ip);//IP地址
boolean status=addr.isReachable(timeOut);// timeOut为等待时间(毫秒)

若status的值为真,则表示该主机是活跃的,否则可能不存在或离线

分析到这里,为了实现一个IP范围的扫描,比如对192.168.11.1到192.168.11.100之间的IP地址进行探测,如何将IP地址正确地输入呢?

我们都知道,IPv4的地址格式是由一个32位二进制数来表示的,为了简单记录,把它分为4个字节,每个字节表示8位,进而使用一个十进制数值来表示

比如192.168.11.1实际就是由4字节32位表示:11000000. 10101000. 00001011. 00000001,192.168.11.100表示为:11000000. 10101000. 00001011. 01100100

观察之后发现,实际就是二进位的变化导致数值的编号的变化,要实现递增的IP地址,可以更为简单的将32位直接表示为一个有符号的十进制数值,前者就是-1062728959,后者是-1062728860。

分析到规律之后,接下来实现这个算法。

四、核心算法

很明显,我们需要两个算法:IP地址转为十进制数和十进制数转为IP地址

首先,确定一个IP地址范围就需要将起始IP以及结束IP地址转化为十进制数值表示,两端边界就是IP地址的区间,然后在这个区间不断递增,将每个数值转为IP地址进而才能输入判断是否可达。

1、IP地址转化为十进制数

这个算法只涉及按位或运算,相对简单。

    public static int ipToLong(String ip) {
        String[] ipArray = ip.split("\\\\.");
        int num = 0;
        for (int i = 0; i < ipArray.length; i++) {
            int valueOfSection = Integer.parseInt(ipArray[i]);//将8位字符串转化为整型
            //对每段ip值左移,再进行按位或运算,最后得到一个十进制数值
            num = (valueOfSection << 8 * (3 - i)) | num;
        }
        return num;
    }

2、十进制数转化为IP地址

这个过程是上面算法的逆过程,主要涉及按位与无符号右移

public static String longToIp(int num) {

    String[] ipString = new String[4];
    for (int i = 0; i < 4; i++) {
        //将数值每8位跟 11111111 按位与运算,得到8位的二进制数
        int and = num & (255 << (8 * (3 - i)));
        //再将每段进行无符号右移,得到每段的ip值
        ipString[i] = String.valueOf(and >>> (8 * (3 - i)));
    }
    String ip = String.join(".", ipString);//将字符串数组拼接为IP地址形式
    return ip;
}

五、主机 IP 扫描神器界面

核心部分已经分析并且完成算法实现,现在来组装IP扫描神器的界面了,这个就很简单啦!

先来看看界面,如图。看到这里,是否跟你想象的一样呢?

可以看到这里除了主机IP扫描的功能,还有一个类似CMD执行命令的功能,后面会简单介绍。

界面代码:

/**
 *  HostScannerFX.java
 *  @author Charzous
 *  @date 2021-05-30 下午 07:03
 *  Copyright (c) 2020-10-30
 *  All right reserved.
 *
 */

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;

public class HostScannerFX extends Application {
    private TextArea result = new TextArea();
    private TextField begin = new TextField();
    private TextField end = new TextField();
    private TextField tfCmd = new TextField();
    private Button PCScan = new Button("主机扫描");
    private Button stop=new Button("停止");
    private Button exeCmd = new Button("执行命令");
    private Thread readThread;

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane mainPane = new BorderPane();
        VBox vBox = new VBox();
        vBox.setSpacing(10);
        vBox.setPadding(new Insets(10, 20, 10, 20));
        VBox.setVgrow(result, Priority.ALWAYS);
        vBox.getChildren().addAll(new Label("扫描结果:"), result);
        mainPane.setCenter(vBox);

        HBox hBox1 = new HBox();
        hBox1.setSpacing(10);
        hBox1.setPadding(new Insets(10, 20, 10, 20));
        hBox1.setAlignment(Pos.CENTER);
        begin.setPrefWidth(180);
        end.setPrefWidth(180);
        hBox1.getChildren().addAll(new Label("起始地址:"), begin, new Label("结束地址:"), end, PCScan,stop);

        HBox hBox2 = new HBox();
        hBox2.setSpacing(10);
        hBox2.setPadding(new Insets(10, 20, 10, 20));
        hBox2.setAlignment(Pos.CENTER);
        HBox.setHgrow(tfCmd, Priority.ALWAYS);
        hBox2.getChildren().addAll(new Label("输入命令格式:"), tfCmd, exeCmd);

        VBox vBox1 = new VBox();
        vBox1.setSpacing(10);
        vBox1.setPadding(new Insets(10, 20, 10, 20));
        vBox1.setAlignment(Pos.CENTER);
        vBox1.getChildren().addAll(hBox1, hBox2);
        mainPane.setBottom(vBox1);

        Scene scene = new Scene(mainPane, 800, 500);
        primaryStage.setScene(scene);
        primaryStage.setTitle("MyHostScanner");
        primaryStage.show();
        
        //关闭窗口
        primaryStage.setOnCloseRequest(event -> {
            System.exit(0);
        });
    }
}

 现在这个还是不能用的,我们需要对界面的按钮绑定事件,也就是将上面的IP探测扫描功能加进来,具体看下面。

六、各功能代码及IP扫描演示

1、主机扫描按钮

上面分析过,扫描探测就是通过ICMP建立通信,这需要耗时,因此将扫描任务放到一个线程中执行,不影响主程序操作。

        PCScan.setOnAction(event -> {
            String host = begin.getText().trim();
            String endHost = end.getText().trim();

            if (host.equals("")||endHost.equals("")){
                result.appendText("请正确输入起始地址和结束地址!\\n");
                return;
            }

            int beginIp = ipToLong(host);
            int endIp = ipToLong(endHost);

            readThread = new Thread(() -> {

                for (int i = beginIp; i <= endIp; i++) {
                    //判断线程状态标志,如果被终止则停止线程
                    if (readThread.isInterrupted()){
                        readThread.interrupt();
                        result.appendText("终止扫描!");
                        break;
                    }
                    String ip = longToIp(i);
                    try {
                        InetAddress address = InetAddress.getByName(ip);
                        boolean status = address.isReachable(200);
                        Platform.runLater(() -> {
                            if (status == true)
                                result.appendText(address + " is reachable.\\n");
                            else
                                result.appendText(address + " is not reachable.\\n");
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                result.appendText("扫描结束!\\n");
            });
            readThread.start();

        });

2、停止按钮

停止的意思就是我们不然程序继续扫描了,终止线程操作,很简单的实现。

        stop.setOnAction(event -> {
            readThread.interrupt();
        });

这个是结合上面扫描线程中,判断线程状态共同实现的。

//判断线程状态标志,如果被终止则停止线程
if (readThread.isInterrupted()){
    readThread.interrupt();
     result.appendText("终止扫描!");
     break;
}

3、执行命令按钮

执行命令是增加的一个功能,主要使用Java里面的Process类和Runtime类共同实现的,类似在命令提示符cmd中输入命令执行功能。

        exeCmd.setOnAction(event -> {
            String cmd=tfCmd.getText();
            if (cmd.equals("")){
                result.appendText("请正确输入执行命令!\\n");
                return;
            }

            readThread = new Thread(()->{
                try {
                    Process process = Runtime.getRuntime().exec(cmd);
                    InputStream in = process.getInputStream();
                    BufferedReader br=new BufferedReader(new InputStreamReader(in,"gbk"));

                    String msg=null;
                        while ((msg=br.readLine())!=null){
                            String msgTemp=msg;
                            Platform.runLater(()->{
                                result.appendText(msgTemp+"\\n");
                            });
                        }
                }
                catch (IOException e) {
                    System.err.println(e.getMessage());
                }
            });
            readThread.start();
        });

现在看看效果了。我所在的局域网的网络是10.173.40.0,我的IP地址是10.173.40.25,所以进行了一个小范围的探测扫描,发现几个IP地址也是活动状态。

然后,查看一下百度的IP地址,扫描看看。

发现百度所在的网段许多IP地址是活动的。

最后

今天来用Java开发主机IP扫描神器,零基础Socket编程详细教程,这篇内容是不是简单、有趣、有收获呢?欢迎交流学习!

学习Java开发,Socket网络编程等知识,里面有许多有趣的小程序可以做,最近我也在跟着这一套 《Java 工程师学习成长知识图谱》进行体系的学习,是CSDN官方推出的,质量很不错!其中包含了Java专业体系结构完整详细,推荐给大家学习使用,有兴趣可以扫码查看,最近我也在学习当中,当然,我的文章会记录学习,欢迎大家阅读,比如我的专栏《Socket网络编程》、《Java宝藏》。

展开就是这样的,尺寸870mm*560mm排版好看,内容很充实。推荐给有需要的伙伴,一起来学习Java开发!


如果觉得不错欢迎“一键三连”哦,点赞收藏关注,评论提问建议,欢迎交流学习!一起加油进步! 

本篇内容首发我的CSDN博客:https://csdn-czh.blog.csdn.net/article/details/117403031

以上是关于今天用Java开发主机IP扫描神器,零基础Socket编程详细的主要内容,如果未能解决你的问题,请参考以下文章

韩顺平循序渐进学Java零基础 第21章 网络编程

扫描神器--nmap

网络安全-端口扫描神器Nmap使用详解与参数指导

卧槽,又一个Java面试神器!

端口扫描神器 - Nmap的基本使用

14. nmap扫描神器总结