You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Minecraft服务器扫描程序实现断点续扫功能

解决Minecraft服务器扫描器的断点续扫问题

问题描述

我开发了一款Minecraft服务器扫描器,可生成0.0.0.0至255.255.255.255范围内的IP地址,并扫描这些IP的25565端口以查找Minecraft Java服务器。

目前已实现程序关闭时将offsetIPs变量值写入offset.mcscan文件,重启时会读取该文件中的值,但不知道如何修改嵌套for循环,使扫描从offsetIPs对应的IP位置继续进行。例如,当扫描64个IP后关闭程序,文件中会写入64,重启后需从第64个IP(对应1.0.0.63)之后的1.0.0.64开始扫描后续IP。

原代码片段

JFrame frame = new JFrame("MCScanner v" + version);
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.setSize(300, 100);
frame.setLayout(new BorderLayout());
frame.addWindowListener(new java.awt.event.WindowAdapter() {
    @Override
    public void windowClosing(java.awt.event.WindowEvent windowEvent) {
        logger.log(Level.INFO, "Stopping threads...");
        for (Thread nextThread: threadList) {
            nextThread.interrupt();
        }
        logger.log(Level.INFO, "Making an 'offset.mcscan'...");
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter("offset.mcscan"));
            writer.write(Long.toString(offsetIPs));
            writer.close();
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Failed to write 'offset.mcscan'!");
        }
        logger.log(Level.INFO, "Exiting...");
        System.exit(0);
    }
});
long scanned = 0;
long offsetIPs = 0;

...

frame.setVisible(true);

File offsetFile = new File("offset.mcscan");
if (offsetFile.exists()) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(offsetFile));
        offsetIPs = Long.parseLong(reader.readLine());
        reader.close();
    } catch (IOException e) {
        logger.log(Level.SEVERE, "Failed to read 'offset.mcscan'!");
    }
}

// this is where I need to implement offsetIPs, but how?
for (int i = minimumRange; i <= maxRange; ++i) {
    for (int j = 0; j <= 255; ++j) {
        for (int k = 0; k <= 255; ++k) {
            for (int l = 0; l <= 255; ++l) {
                String ip = i + "." + j + "." + k + "." + l;

                ScannerThread scannerThread = new ScannerThread(ip, port, timeout, databaseHandler);
                Thread scanThread = new Thread(scannerThread);
                threadList.add(scanThread);
                scanThread.start();

                if (threadList.size() >= threads.get()) {
                    for (Thread nextThread: threadList) {
                        try {
                            nextThread.join();
                            ++scanned;
                            ++offsetIPs;
                            scannedLabel.setText("Scanned: " + scanned + "/" + progressThing * 256 + " (" + Math.round((scanned / (progressThing * 256)) * 100) / 100 + "%)");
                        } catch (InterruptedException timeout2) {
                            // eh
                        }
                    }
                    threadList.clear();
                }
            }
        }
    }
}

for (Thread nextThreadAgain: threadList) {
    try {
        nextThreadAgain.join();
        ++offsetIPs;
        ++scanned;
        // progressBar.setValue(scanned);
        scannedLabel.setText("Scanned: " + scanned + "/" + progressThing * 256);
    } catch (InterruptedException timeout1) {
        // well
    }
}

解决方案

核心是将offsetIPs(已扫描的IP总数)转换为对应的四段IP数值,然后调整循环起始值,跳过已扫描的IP:

1. 计算偏移对应的IP段

在读取offsetIPs后,添加以下代码计算对应的四段IP值:

// 将offsetIPs转换为对应的IP段
long totalPerFirst = 256L * 256 * 256;
long totalPerSecond = 256L * 256;
long totalPerThird = 256L;

int startI = (int) (offsetIPs / totalPerFirst);
int startJ = (int) ((offsetIPs / totalPerSecond) % 256);
int startK = (int) ((offsetIPs / totalPerThird) % 256);
int startL = (int) (offsetIPs % 256);

// 确保起始段不小于minimumRange
if (startI < minimumRange) {
    startI = minimumRange;
    startJ = 0;
    startK = 0;
    startL = 0;
}

2. 修改嵌套循环的起始值

替换原来的嵌套循环,根据计算出的起始值开始循环,并添加跳过逻辑:

// 修改后的循环,支持断点续扫
for (int i = startI; i <= maxRange; ++i) {
    // 确定当前i段的起始j值
    int currentStartJ = (i == startI) ? startJ : 0;
    for (int j = currentStartJ; j <= 255; ++j) {
        // 确定当前j段的起始k值
        int currentStartK = (i == startI && j == startJ) ? startK : 0;
        for (int k = currentStartK; k <= 255; ++k) {
            // 确定当前k段的起始l值
            int currentStartL = (i == startI && j == startJ && k == startK) ? startL : 0;
            for (int l = currentStartL; l <= 255; ++l) {
                // 计算当前IP对应的偏移量,跳过已扫描的部分
                long currentOffset = (long)i * totalPerFirst + (long)j * totalPerSecond + (long)k * totalPerThird + l;
                if (currentOffset < offsetIPs) {
                    continue;
                }

                String ip = i + "." + j + "." + k + "." + l;

                ScannerThread scannerThread = new ScannerThread(ip, port, timeout, databaseHandler);
                Thread scanThread = new Thread(scannerThread);
                threadList.add(scanThread);
                scanThread.start();

                if (threadList.size() >= threads.get()) {
                    for (Thread nextThread: threadList) {
                        try {
                            nextThread.join();
                            ++scanned;
                            ++offsetIPs;
                            scannedLabel.setText("Scanned: " + scanned + "/" + progressThing * 256 + " (" + Math.round((scanned / (progressThing * 256)) * 100) / 100 + "%)");
                        } catch (InterruptedException timeout2) {
                            // 处理中断
                        }
                    }
                    threadList.clear();
                }
            }
        }
    }
}

关键说明

  • IP偏移计算:每个IP段对应的总IP数分别是256^3(第一段)、256^2(第二段)、256(第三段),通过除法和取模运算可以将offsetIPs转换为对应的四段数值。
  • 循环起始值调整:针对每一段循环,只有当处于起始IP段时才使用计算出的起始值,否则从0开始,避免跳过未扫描的IP。
  • 跳过逻辑:计算当前IP对应的偏移量,如果小于offsetIPs则直接跳过,确保不会重复扫描已完成的IP。

内容的提问来源于stack exchange,提问作者KnotAnotherOne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:50:55