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

Java Socket 經典範例:Echo Server/Client 完整實作與運行指南

     編輯:Java 相關知識

前言:最小可行性網路程式

Echo 服務是網路程式設計的「Hello World」。伺服端接收客戶端傳送的文字,原樣回傳 (加前綴 "Echo: "),直到雙方約定結束 (輸入 "BYE")。本文提供完整、可直接編譯運行的 EchoServer1、EchoClient1 原始碼,並詳解關鍵 API、執行步驟與常見錯誤。

伺服端程式碼

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

public class EchoServer1 {
    public static void main(String[] args) {
        try (ServerSocket server = new ServerSocket(8500)) {
            System.out.println("Echo Server started on port 8500. Waiting for client...");
            try (Socket client = server.accept();
                 BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
                 PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream(), StandardCharsets.UTF_8), true)) {
                
                out.println("Hello! Enter BYE to exit.");
                String line;
                while ((line = in.readLine()) != null) {
                    if (line.trim().equalsIgnoreCase("BYE")) {
                        out.println("Echo: BYE - Goodbye!");
                        break;
                    }
                    out.println("Echo: " + line);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客戶端程式碼

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

public class EchoClient1 {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java EchoClient1 ");
            return;
        }
        String host = args[0];
        int port = 8500;
        try (Socket socket = "localhost".equals(host) ? 
                new Socket(InetAddress.getLocalHost(), port) : 
                new Socket(InetAddress.getByName(host), port);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
            
            System.out.println("Connected to " + host + ":" + port);
            String serverMsg = in.readLine(); // 讀取歡迎訊息
            System.out.println("Server: " + serverMsg);
            
            String input;
            while ((input = console.readLine()) != null) {
                out.println(input); // 發送給伺服器
                if ("bye".equalsIgnoreCase(input)) break;
                String echo = in.readLine(); // 讀取回應
                System.out.println("Server: " + echo);
            }
        } catch (UnknownHostException e) {
            System.err.println("Unknown host: " + host);
        } catch (IOException e) {
            System.err.println("I/O Error: " + e.getMessage());
        }
    }
}

關鍵 API 與設計細節

API用途關鍵參數
ServerSocket(int port)建立伺服器監聽埠口port=8500,0 表系統自動分配
server.accept()阻塞等待客戶端連線,返回新 Socket每個客戶端對應一個 Socket
Socket(InetAddress, int)客戶端主動連線支援 hostname 或 IP
BufferedReader行導向讀取 (以 \n/\r\n 分隔)包裝 InputStreamReader 指定 UTF-8
PrintWriter(..., true)行導向寫入,autoFlush=true呼叫 println() 自動 flush()
try-with-resourcesJDK 7+ 自動關閉資源確保 Socket/Stream 正確釋放

編譯與運行步驟

  1. 儲存檔案:EchoServer1.java、EchoClient1.java
  2. 編譯:
    javac EchoServer1.java
    javac EchoClient1.java
  3. 啟動伺服端 (終端機 1):
    java EchoServer1
    輸出:Echo Server started on port 8500. Waiting for client...
  4. 啟動客戶端 (終端機 2):
    java EchoClient1 localhost
    或跨機器:java EchoClient1 192.168.1.100
  5. 互動測試:客戶端終端機輸入文字,觀察伺服端回傳 "Echo: ...",輸入 BYE 結束。

常見錯誤與排查

錯誤現象原因解決
Connection refused伺服端未啟動、埠口錯誤、防火牆攔截確認伺服端運行、埠口一致、防火牆放行 8500
BindException: Address already in use埠口被佔用 (前次進程未完全釋放)lsof -i :8500 找到 PID kill,或換埠口
中文亂碼編碼不一致 (伺服端/客戶端/終端機)統一指定 StandardCharsets.UTF_8,終端機設定 UTF-8
客戶端輸入無回應伺服端未 flush() 或客戶端 readLine() 等待換行符PrintWriter(..., true) 啟用 autoFlush,確保發送 \n
UnknownHostException主機名無法解析用 IP 替代、檢查 /etc/hosts 或 DNS

進階擴充練習

  1. 多執行緒伺服器:將 accept() 後的處理移入 new Thread(() -> handle(client)).start(),支援多客戶端同時連線。
  2. 加入時間戳:伺服端回傳 "Echo [" + Instant.now() + "]: " + line。
  3. 指令擴充:解析 /time 回傳伺服器時間、/ip 回傳客戶端 IP。
  4. SSL 加密:改用 SSLServerSocketFactory/SSLSocketFactory,需產生 keystore。
  5. NIO 非阻塞版:使用 ServerSocketChannel、Selector 實現單執行緒高併發。

總結

Echo 範例雖簡單,却涵蓋了 Java Socket 程式設計的完整生命週期:ServerSocket → accept() → Stream → readLine()/println() → close()。掌握此範例,即掌握了所有 TCP 文字協定 (HTTP、SMTP、POP3、IRC、自訂協定) 的開發基礎。建議動手運行、修改、擴充,建立肌肉記憶。

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