如何为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
相关产品推荐
相关产品推荐

