本文完整實現基於 TCP 協定的並發圖片上傳系統,涵蓋客戶端/伺服端架構、多線程併發處理、檔案命名衝突解決、命令列參數校驗等工程級細節。
ServerSocket.accept() 循環監聽 → 每個連線啟動獨立執行緒處理 → 接收資料寫入檔案 → 回傳結果。// 伺服端主循環
while (true) {
Socket socket = serverSocket.accept();
new Thread(new UploadPicServerThread(socket)).start(); // 核心:分派執行緒
}
// 執行緒任務類
class UploadPicServerThread implements Runnable {
private final Socket socket;
public UploadPicServerThread(Socket s) { this.socket = s; }
@Override public void run() { /* 處理單個客戶端上傳邏輯 */ }
}
String ip = socket.getInetAddress().getHostAddress(); // 獲取客戶端 IP
int fileNum = 1;
File file = new File(ip + ".png");
while (file.exists()) { // 衝突則遞增序號
file = new File(ip + "(" + (fileNum++) + ").png");
}
// 例如:192.168.1.100.png → 192.168.1.100(1).png → 192.168.1.100(2).png
// 必須且僅有一個參數
if (args.length != 1) { System.out.println("請選擇一個文件"); return; }
File file = new File(args[0]);
// 必須存在、是檔案、副檔名 .png、大小 ≤ 1MB
if (!file.exists() || !file.isFile() ||
!file.getName().endsWith(".png") || file.length() > 1024*1024) {
System.out.println("請選擇小於1M的png文件"); return;
}
// 客戶端發送
OutputStream out = socket.getOutputStream();
FileInputStream fis = new FileInputStream(localFile);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) out.write(buffer, 0, len);
socket.shutdownOutput(); // 關鍵:告知伺服端「發送完畢」
// 接收回饋
InputStream in = socket.getInputStream();
byte[] resp = new byte[1024];
len = in.read(resp);
System.out.println(new String(resp, 0, len));
// 伺服端接收並回饋
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
while ((len = is.read(buffer)) != -1) fos.write(buffer, 0, len);
OutputStream os = socket.getOutputStream();
os.write("上傳成功!".getBytes());
ExecutorService 限制併發數,防止連線風暴耗盡資源。此實戰案例展示了 Java 網絡編程從「能跑通」到「可生產」的關鍵躍升點。