本質上是兩個行程通訊:Server 提供固定位置(IP + Port),Client 主動連線。Java 在 java.net 封裝底層細節,核心類別:ServerSocket、Socket、InetAddress。
ServerSocket server = new ServerSocket(5678); // 埠號 > 1024
Socket client = server.accept(); // 阻塞等待連線
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true); // auto-flush
while (true) {
String str = in.readLine();
System.out.println("收到: " + str);
out.println("has receive....");
if ("end".equalsIgnoreCase(str)) break;
}
client.close();
Socket server = new Socket(InetAddress.getLocalHost(), 5678);
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter out = new PrintWriter(server.getOutputStream(), true);
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = keyboard.readLine()) != null) {
out.println(line);
if ("end".equalsIgnoreCase(line)) break;
System.out.println("伺服器回應: " + in.readLine());
}
server.close();
外層 while(true) 迴圈接受連線,但同一時間只能服務一個客戶(排隊):
while (true) {
Socket client = server.accept();
// 處理單一客戶完整對話...
client.close();
}
每個連線派生獨立執行緒處理,實現真正並發:
public class MultiUserServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(5678);
System.out.println("伺服器啟動,監聽埠 5678...");
while (true) {
Socket client = server.accept();
new ClientHandler(client).start(); // 啟動執行緒
}
}
}
class ClientHandler extends Thread {
private final Socket client;
public ClientHandler(Socket socket) { this.client = socket; }
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
String line;
while ((line = in.readLine()) != null) {
System.out.println("[" + client.getInetAddress() + "] " + line);
out.println("has receive....");
if ("end".equalsIgnoreCase(line)) break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try { client.close(); } catch (IOException ignored) {}
}
}
}
關鍵點:執行緒透過建構子傳遞 Socket 參考,各自擁有獨立 I/O 通道。生產環境建議使用執行緒池(ExecutorService)限制並發數量。
InputStreamReader/OutputStreamWriter 轉為字元流。BufferedReader.readLine() 以換行符為界,適合文本協議。PrintWriter 建構子啟用 autoFlush=true 確保 println 即時發送。