首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 線程池實戰:TCP 端口掃描器實現

     編輯:Java 相關知識

利用 JDK 1.5+ ExecutorService 線程池技術,實現高效 TCP 端口掃描器。核心採用固定大小線程池並行嘗試連接目標 IP 端口,避免逐個串行掃描的低效與無限制建立線程的資源耗盡風險。

核心掃描邏輯

private void scanLocal() {
    String ip = getLocalIP();
    String portStart = txPortStart1.getText().trim();
    String portEnd = txPortEnd1.getText().trim();
    if (portStart.isEmpty() || portEnd.isEmpty()) return;
    
    int startPort, endPort;
    try {
        startPort = Integer.parseInt(portStart);
        endPort = Integer.parseInt(portEnd);
    } catch (Exception ex) {
        JOptionPane.showMessageDialog(null, "端口輸入有誤");
        return;
    }
    if (!validPort(startPort) || !validPort(endPort)) {
        JOptionPane.showMessageDialog(null, "端口應在 1-65535 範圍");
        return;
    }
    
    scan(ip, startPort, endPort);
    monitorScanCompletion(); // 監控掃描完成
}

private String getLocalIP() {
    try { return InetAddress.getLocalHost().getHostAddress(); }
    catch (Exception e) { JOptionPane.showMessageDialog(null, "獲取 IP 失敗"); return null; }
}

private void scan(String ip, int startPort, int endPort) {
    setButtonsEnabled(false);
    status.setText("請稍候...");
    tableModel.addRow(new Object[]{ip, ""});
    
    ExecutorService exec = Executors.newFixedThreadPool(10); // 固定 10 線程池
    for (int port = startPort; port <= endPort; port++) {
        exec.execute(new PortScannerTask(ip, port));
    }
    exec.shutdown(); // 不再接受新任務,等待現有任務完成
}

掃描任務實現

class PortScannerTask implements Runnable {
    private final String ip;
    private final int port;
    
    PortScannerTask(String ip, int port) { this.ip = ip; this.port = port; }
    
    public void run() {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(ip, port), 200); // 200ms 連接超時
            // 連接成功 → 端口開放
            SwingUtilities.invokeLater(() -> 
                updateResult(port, "開放"));
        } catch (IOException e) {
            // 連接失敗 → 端口關閉/過濾,可選記錄
        }
    }
}

關鍵設計優勢

  1. 受控並發:固定 10 線程池,避免掃描 65535 端口時建立海量線程導致 OOM
  2. 超時控制:socket.connect(..., 200) 設定連接超時,防止阻塞過久
  3. UI 線程安全:結果更新用 SwingUtilities.invokeLater() 切回 EDT
  4. 優雅關閉:exec.shutdown() 等待所有任務完成,配合監控線程檢測 isTerminated() 恢復 UI 狀態

監控掃描完成

private void monitorScanCompletion() {
    new Thread(() -> {
        while (!exec.isTerminated()) {
            try { Thread.sleep(500); } catch (InterruptedException ignored) {}
        }
        SwingUtilities.invokeLater(() -> {
            setButtonsEnabled(true);
            status.setText("掃描完成");
        });
    }).start();
}

擴展建議

  • 使用 CompletableFuture 替代 Runnable,支援結果聚合與異常處理
  • 加入掃描進度條:原子計數器統計已完成任務數
  • 支援多目標 IP 範圍掃描,結合 ExecutorCompletionService 取得最快結果
  • 整合 Nmap 風格指紋識別,進一步判斷服務版本
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved