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

Java Socket 檔案傳輸完整實現:伺服端與客戶端代碼詳解

     編輯:Java 相關知識

架構概覽

  • Server:監聽埠、接受連線、讀取本地檔案、發送檔名/大小/內容。
  • Client:連線伺服器、發送握手訊息、接收檔案資訊與內容、寫入磁碟。
  • 工具類:封裝 Socket 連線、發送/接收流操作。

核心協議設計

  1. 客戶端連線後發送握手字串(如 "Windows"),伺服端讀取確認。
  2. 伺服端發送:UTF-8 檔名 → long 檔案大小 → 檔案位元組流。
  3. 客戶端按序讀取,寫入本地檔案,顯示進度。

1. 工具類:ClientSocket

public class ClientSocket {
    private final String host;
    private final int port;
    private Socket socket;
    private DataOutputStream out;
    private DataInputStream in;

    public ClientSocket(String host, int port) { this.host = host; this.port = port; }

    public void connect() throws IOException {
        socket = new Socket(host, port);
        out = new DataOutputStream(socket.getOutputStream());
        in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    }

    public void sendHandshake(String msg) throws IOException {
        out.writeUTF(msg); out.flush();
    }

    public DataInputStream getInputStream() { return in; }

    public void close() {
        try { if (out != null) out.close(); } catch (IOException ignored) {}
        try { if (in != null) in.close(); } catch (IOException ignored) {}
        try { if (socket != null) socket.close(); } catch (IOException ignored) {}
    }
}

2. 伺服端:FileServer

public class FileServer {
    private static final int PORT = 8821;
    private static final String FILE_PATH = "E:/lib.zip"; // 待傳送檔案
    private static final int BUFFER_SIZE = 8192;

    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(PORT);
        System.out.println("伺服器啟動,監聽埠:" + PORT);

        while (true) {
            Socket client = server.accept();
            System.out.println("客戶端連線:" + client.getInetAddress());
            
            new Thread(() -> handleClient(client)).start(); // 多線程併發
        }
    }

    private static void handleClient(Socket socket) {
        try (DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
             DataOutputStream out = new DataOutputStream(socket.getOutputStream());
             FileInputStream fis = new FileInputStream(FILE_PATH)) {

            File file = new File(FILE_PATH);
            // 讀取握手(簡單示範)
            in.readUTF();

            // 發送檔案元資料
            out.writeUTF(file.getName());
            out.writeLong(file.length());
            out.flush();

            // 發送檔案內容
            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush();
            System.out.println("檔案傳輸完成:" + file.getName());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try { socket.close(); } catch (IOException ignored) {}
        }
    }
}

3. 客戶端:FileClient

public class FileClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 8821;
    private static final String SAVE_DIR = "F:/";
    private static final int BUFFER_SIZE = 8192;

    public static void main(String[] args) {
        ClientSocket cs = new ClientSocket(SERVER_HOST, SERVER_PORT);
        try {
            cs.connect();
            cs.sendHandshake("Windows"); // 簡單握手
            
            DataInputStream in = cs.getInputStream();
            String fileName = in.readUTF();
            long fileSize = in.readLong();
            
            File outFile = new File(SAVE_DIR + fileName);
            try (DataOutputStream fos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)))) {
                byte[] buffer = new byte[BUFFER_SIZE];
                int len, totalRead = 0;
                while ((len = in.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                    totalRead += len;
                    System.out.printf("進度:%.2f%%%n", (totalRead * 100.0) / fileSize);
                }
                System.out.println("接收完成,儲存至:" + outFile.getAbsolutePath());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            cs.close();
        }
    }
}

關鍵技術點總結

  1. DataInput/OutputStream:提供 writeUTF/readUTF(長度前綴字串)、writeLong/readLong 等跨平台序列化方法。
  2. 緩衝流包裝:BufferedInput/OutputStream 大幅減少系統調用,提升吞吐。
  3. 檔案大小預傳:客戶端預知總大小,可顯示進度、分配空間、驗證完整性。
  4. 多線程併發:伺服端每連線開一執行緒(或用線程池),支援多客戶端同時下載。
  5. 資源關閉順序:流 → Socket,避免「寫端關閉導致讀端阻塞」或資源洩漏。

擴展建議

  • 斷點續傳:客戶端發送已接收位移,伺服端 RandomAccessFile.seek() 續傳。
  • 校驗完整性:傳輸前計算 MD5/SHA256,傳輸後驗證。
  • SSL/TLS 加密:SSLSocketFactory 保護資料機密性。
  • NIO/Netty 重構:高併發場景下替換 BIO,提升擴展性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved