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

Java Socket 發送文件到伺服器端完整實現指南

     編輯:Java 相關知識

Java Socket 文件傳輸:客戶端發送文件到伺服器完整實現

本文提供基於 Java Socket 的文件傳輸完整代碼,實現客戶端讀取本地文件透過 TCP 發送至伺服器,伺服器接收寫入磁碟並回傳確認訊息。

核心功能流程

  1. 客戶端建立 Socket 連接伺服器 IP:Port
  2. 使用 BufferedReader 讀取本地文件 (逐行)
  3. 透過 PrintWriter 寫入 Socket 輸出流
  4. 客戶端關閉輸出流 (shutdownOutput()) 標記傳輸結束
  5. 伺服器循環讀取輸入流寫入目標文件
  6. 伺服器發送「上傳成功」確認訊息
  7. 雙向關閉流與 Socket

完整代碼實現

發送端 - send2 類

import java.io.*;
import java.net.*;

class send2 {
    public static void main(String[] args) throws Exception {
        // 1. 建立連接
        Socket socket = new Socket("192.168.33.1", 10005);
        
        // 2. 讀取本地文件
        BufferedReader fileReader = new BufferedReader(new FileReader("io.java"));
        
        // 3. 獲取網路輸出流,自動 flush
        PrintWriter netOut = new PrintWriter(socket.getOutputStream(), true);
        
        // 4. 逐行讀取並發送
        String line;
        while ((line = fileReader.readLine()) != null) {
            netOut.println(line);
        }
        
        // 5. 關鍵:關閉輸出流,發送 EOF 信號
        socket.shutdownOutput();
        
        // 6. 接收伺服器回應
        BufferedReader netIn = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        String response = netIn.readLine();
        System.out.println("伺服器回應: " + response);
        
        // 7. 關閉資源
        fileReader.close();
        socket.close();
    }
}

接收端 - rece2 類

import java.io.*;
import java.net.*;

class rece2 {
    public static void main(String[] args) throws Exception {
        // 1. 建立伺服器 Socket
        ServerSocket serverSocket = new ServerSocket(10005);
        
        // 2. 接受客戶端連接 (阻塞)
        Socket socket = serverSocket.accept();
        
        // 3. 讀取網路輸入流
        BufferedReader netIn = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
        
        // 4. 寫入本地文件
        PrintWriter fileOut = new PrintWriter(new FileWriter("io2.txt"), true);
        
        String line;
        while ((line = netIn.readLine()) != null) {
            // 可選:特殊標記結束
            // if ("over".equals(line)) break;
            fileOut.println(line);
        }
        
        // 5. 發送成功確認
        PrintWriter netOut = new PrintWriter(socket.getOutputStream(), true);
        netOut.println("上傳成功!");
        
        // 6. 關閉資源 (順序很重要)
        fileOut.close();
        serverSocket.close();
        socket.close();
    }
}

關鍵技術點深度解析

1. shutdownOutput() 的關鍵作用

  • 發送 TCP FIN 包,通知對端「資料發送完畢」
  • 對端 readLine() 返回 null,read() 返回 -1
  • 若不調用,伺服器會永遠阻塞在 readLine() 等待更多資料
  • 注意:只關閉輸出流,輸入流仍可接收伺服器回應

2. PrintWriter 自動 flush 機制

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// 第二參數 true = autoFlush,每次 println/printf/format 後自動 flush

確保資料即時發送,不滯留在緩衝區。

3. 文字 vs 二進位傳輸

模式適用場景類別注意事項
文字模式原始碼、配置、日誌、CSV 等文本文件Reader/Writer, PrintWriter, BufferedReader自動處理換行符,編碼需一致 (UTF-8)
二進位模式圖片、視頻、壓縮包、執行檔等二進位文件InputStream/OutputStream, FileInputStream, FileOutputStream使用 byte[] 緩衝區,無編碼轉換,保真度高

二進位模式範例 (通用文件傳輸)

// 發送端
try (FileInputStream fis = new FileInputStream("image.jpg");
     OutputStream out = socket.getOutputStream()) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = fis.read(buffer)) != -1) {
        out.write(buffer, 0, len);
    }
    socket.shutdownOutput();
}

// 接收端
try (InputStream in = socket.getInputStream();
     FileOutputStream fos = new FileOutputStream("received.jpg")) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = in.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
    }
}

4. 資源關閉順序原則

  1. 先關閉應用層流 (FileWriter, PrintWriter 等)
  2. 再關閉網路流 (Socket.getInputStream/OutputStream)
  3. 最後關閉 Socket / ServerSocket
  4. 使用 try-with-resources (JDK 7+) 自動管理

常見問題與解決方案

問題 1:大文件傳輸中斷

原因:網路不穩、緩衝區溢出、無超時設定
方案:

  • 設定 socket.setSoTimeout(30000) 讀取超時
  • 使用較大緩衝區 (8KB-64KB)
  • 實現斷點續傳 (記錄已傳位置)

問題 2:中文檔名/內容亂碼

原因:編碼不一致 (客戶端 UTF-8,伺服器 GBK)
方案:

  • 統一指定編碼 new InputStreamReader(in, "UTF-8")
  • 或使用二進位模式傳輸,避免編碼轉換

問題 3:伺服器無法處理多客戶端

原因:單執行緒 accept() 循環
方案:

  • 每次 accept() 後啟動新 Thread 處理
  • 或使用 ThreadPoolExecutor 線程池
  • 高併發改用 NIO/Netty

生產環境增強建議

  • 協議封裝:定義檔頭 (檔名、大小、MD5、分片資訊)
  • 完整性校驗:傳輸前後計算 MD5/SHA256 比對
  • 加密傳輸:使用 SSLSocket 或自定義加密
  • 進度回調:定期回傳已傳位元組數
  • 限流控制:Token Bucket 演算法限制頻寬
  • 日誌審計:記錄傳輸時間、大小、雙方 IP、結果

總結

Java Socket 文件傳輸核心在於:shutdownOutput() 正確標記結束、二進位模式保真傳輸、資源正確關閉順序。文字模式適合文本文件,二進位模式通用性更強。生產環境需增加協議層、錯誤處理、安全機制與監控能力。

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