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

Java Socket 編程實戰(二):多線程服務端與客戶端完整代碼

     編輯:Java 相關知識

項目結構

  • Server.java:監聽端口、多線程處理連接、文本反轉服務。
  • Client.java:連接服務器、控制台交互、收發文本。

Server.java 完整代碼


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

public class Server extends Thread {
    public final static int DEFAULT_PORT = 6543;
    protected int port;
    protected ServerSocket listenSocket;

    // 統一異常處理:打印並退出
    public static void fail(Exception e, String msg) {
        System.err.println(msg + ": " + e);
        System.exit(1);
    }

    // 構造器:綁定端口、啟動監聽線程
    public Server(int port) {
        if (port == 0) port = DEFAULT_PORT;
        this.port = port;
        try {
            listenSocket = new ServerSocket(port);
        } catch (IOException e) {
            fail(e, "Exception creating server socket");
        }
        System.out.println("Server: listening on port " + port);
        this.start(); // 啟動 run() 監聽循環
    }

    // 監聽線程主體:無限循環 accept,每連接創建 Connection 線程
    public void run() {
        try {
            while (true) {
                Socket clientSocket = listenSocket.accept();
                new Connection(clientSocket); // Connection 構造器內啟動線程
            }
        } catch (IOException e) {
            fail(e, "Exception while listening for connections");
        }
    }

    // 主方法:解析參數啟動服務器
    public static void main(String[] args) {
        int port = 0;
        if (args.length == 1) {
            try { port = Integer.parseInt(args[0]); }
            catch (NumberFormatException e) { port = 0; }
        }
        new Server(port);
    }
}

// 連接處理線程:負責單個客戶端的收發邏輯
class Connection extends Thread {
    protected Socket client;
    protected DataInputStream in;
    protected PrintStream out;

    public Connection(Socket clientSocket) {
        this.client = clientSocket;
        try {
            in = new DataInputStream(client.getInputStream());
            out = new PrintStream(client.getOutputStream());
        } catch (IOException e) {
            try { client.close(); } catch (IOException ignored) {}
            System.err.println("Exception while getting socket stream: " + e);
            return;
        }
        this.start(); // 啟動 run() 處理循環
    }

    public void run() {
        try {
            while (true) {
                String line = in.readLine();     // 讀取一行文本
                if (line == null) break;         // 客戶端關閉
                // 反轉文本
                StringBuffer rev = new StringBuffer(line.length());
                for (int i = line.length() - 1; i >= 0; i--) {
                    rev.append(line.charAt(i));
                }
                out.println(rev.toString());     // 發送反轉結果
            }
        } catch (IOException ignored) {
        } finally {
            try { client.close(); } catch (IOException ignored) {}
        }
    }
}

Client.java 完整代碼


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

public class Client {
    public static final int DEFAULT_PORT = 6543;

    public static void usage() {
        System.out.println("Usage: java Client  [port]");
        System.exit(0);
    }

    public static void main(String[] args) {
        int port = DEFAULT_PORT;
        Socket socket = null;

        // 參數解析
        if (args.length != 1 && args.length != 2) usage();
        if (args.length == 2) {
            try { port = Integer.parseInt(args[1]); }
            catch (NumberFormatException e) { usage(); }
        }

        try {
            // 建立連接
            socket = new Socket(args[0], port);
            DataInputStream in = new DataInputStream(socket.getInputStream());
            PrintStream out = new PrintStream(socket.getOutputStream());
            DataInputStream console = new DataInputStream(System.in);

            System.out.println("Connected to " + socket.getInetAddress() + ":" + socket.getPort());

            // 交互循環
            while (true) {
                System.out.print(" > ");
                System.out.flush();
                String line = console.readLine(); // 讀取控制台輸入
                if (line == null) break;          // EOF (Ctrl+D / Ctrl+Z)
                out.println(line);                // 發送給服務器
                String response = in.readLine();  // 接收服務器響應
                if (response == null) {
                    System.out.println("Connection closed by server.");
                    break;
                }
                System.out.println(response);     // 顯示響應
            }
        } catch (IOException e) {
            System.err.println(e);
        } finally {
            if (socket != null) {
                try { socket.close(); } catch (IOException ignored) {}
            }
        }
    }
}

運行步驟

  1. 編譯:javac Server.java Client.java
  2. 啟動服務端:java Server 6543(端口可省略,默認 6543)
  3. 啟動客戶端:java Client localhost 6543
  4. 客戶端控制台輸入文本,服務端返回反轉文本。輸入 EOF (Ctrl+D / Ctrl+Z) 退出。

核心設計點解析

擴展方向

  • 協議升級:定長/分隔符/長度前綴/Protobuf/JSON,替換 readLine。
  • NIO/Netty:Selector 非阻塞 IO,支撐萬級連接(C10K 問題)。
  • 心跳/重連/超時/SSL/TLS 安全傳輸。
  • 線程池:ExecutorService 替換 new Thread(),控制併發數。

總結

本文提供了基於 ServerSocket/Socket + 多線程的經典 Java 同步阻塞 IO 服務端/客戶端完整實現。代碼結構清晰、邏輯最小化,是學習 Java 網絡編程、理解 BIO 模型、進階 NIO/Netty 的最佳起點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
點說明
ServerSocket服務端專用,accept() 阻塞等待連接,返回新 Socket 處理具體通信。
多線程模型主線程 Server.run() 循環 accept;每連接一個 Connection 線程隔離 IO,互不阻塞。
流選擇DataInputStream.readLine() / PrintStream.println() 按行處理文本,適配控制台交互。
資源釋放finally 確保 socket.close(),防止句柄洩漏。
異常處理統一 fail() 打印並退出,簡化邏輯;生產環境應改為日誌+重試/熔斷。