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

手把手教你用 Java 實現 FTP 伺服器核心協議與多執行緒架構

     編輯:Java 相關知識

FTP 協議核心命令集

FTP 基於雙通道架構:命令通道 (Port 21) 處理控制指令,資料通道 臨時建立傳輸檔案。常用命令分類:

類別命令說明
傳輸模式TYPE A / TYPE IASCII 文本 / Binary 二進制
目錄操作CWD, CDUP, PWD, LIST切換/列舉目錄
連線控制USER, PASS, QUIT認證與斷開
檔案上傳STOR, APPE, MPUT單/多檔上傳
檔案下載RETR, MGET單/多檔下載
資料連接PORT, PASV主動/被動模式協商埠口
檔案管理DELE, RNFR/RNTO, MKD/RMD刪除/重命名/建立刪除目錄

伺服器架構設計:主執行緒 + Worker 執行緒池

public class FtpServer {
    private static String rootDir = "C:/ftp_root"; // 可透過 args[0] 指定
    
    public static void main(String[] args) throws IOException {
        if (args.length > 0) rootDir = args[0];
        
        try (ServerSocket server = new ServerSocket(21)) {
            System.out.println("FTP Server started on port 21, root: " + rootDir);
            ExecutorService pool = Executors.newCachedThreadPool();
            
            while (true) {
                Socket client = server.accept();
                pool.execute(new ClientHandler(client, rootDir));
            }
        }
    }
}

ClientHandler 核心邏輯

1. 歡迎與認證流程

out.println("220 Welcome to Java FTP Server");
String line;
while ((line = in.readLine()) != null) {
    if (line.startsWith("USER ")) {
        username = line.substring(5).trim();
        out.println("331 Password required for " + username);
    } else if (line.startsWith("PASS ")) {
        // 這裡應對接真實認證系統 (DB/LDAP/檔案)
        out.println("230 User " + username + " logged in");
        break; // 進入命令迴圈
    }
}

2. PORT 命令解析 (主動模式關鍵)

客戶端傳送 `PORT h1,h2,h3,h4,p1,p2`,IP = `h1.h2.h3.h4`,Port = `p1*256 + p2`

if (cmd.startsWith("PORT ")) {
    String[] parts = cmd.substring(5).split(",");
    String ip = String.join(".", parts[0], parts[1], parts[2], parts[3]);
    int port = Integer.parseInt(parts[4]) * 256 + Integer.parseInt(parts[5]);
    dataSocket = new Socket(ip, port); // 主動連回客戶端
    out.println("200 PORT command successful");
}

3. 檔案傳輸實現 (RETR / STOR)

// RETR 下載
if (cmd.startsWith("RETR ")) {
    String fileName = cmd.substring(5).trim();
    File file = new File(currentDir, fileName);
    out.println("150 Opening BINARY data connection for " + fileName);
    try (FileInputStream fis = new FileInputStream(file);
         OutputStream dos = dataSocket.getOutputStream()) {
        byte[] buf = new byte[8192];
        int len;
        while ((len = fis.read(buf)) > 0) dos.write(buf, 0, len);
    }
    out.println("226 Transfer complete");
}

// STOR 上傳
if (cmd.startsWith("STOR ")) {
    String fileName = cmd.substring(5).trim();
    File file = new File(currentDir, fileName);
    out.println("150 Opening BINARY data connection for " + fileName);
    try (InputStream dis = dataSocket.getInputStream();
         FileOutputStream fos = new FileOutputStream(file)) {
        byte[] buf = new byte[8192];
        int len;
        while ((len = dis.read(buf)) > 0) fos.write(buf, 0, len);
    }
    out.println("226 Transfer complete");
}

4. 目錄列表 (LIST)

if (cmd.equals("LIST")) {
    out.println("150 Here comes the directory listing");
    try (PrintWriter pw = new PrintWriter(dataSocket.getOutputStream())) {
        File[] files = currentDir.listFiles();
        for (File f : files) {
            String perm = f.isDirectory() ? "drwxr-xr-x" : "-rw-r--r--";
            pw.printf("%s 1 owner group %12d %s %s%n",
                perm, f.length(), 
                new SimpleDateFormat("MMM dd HH:mm").format(new Date(f.lastModified())),
                f.getName());
        }
    }
    out.println("226 Directory send OK");
}

生產級擴展建議

  • 被動模式 (PASV/EPSV):伺服器開啟隨機埠供客戶端連入,解決 NAT/防火牆問題
  • TLS/SSL 加密 (FTPS):`SSLServerSocketFactory` 保護認證與傳輸
  • 虛擬使用者體系:資料庫存儲帳號、家目錄、權限、頻寬限制
  • 斷點續傳:`REST` 命令 + `RandomAccessFile` seek
  • 日誌審計:記錄 IP、用戶、命令、傳輸大小、耗時

完整原始碼可參考 Apache Mina FtpServer 或 FTP4J 等成熟開源實現,生產環境建議直接整合而非自建。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved