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

Java Socket 網絡編程全解析:從 BIO 到 NIO、客戶端/服務端、多線程與連接池實戰

     編輯:Java 相關知識

網絡編程基石:客戶端/服務端模型

如同餐廳點餐:客戶端 (食客) 發起請求 → 服務端 (廚房) 處理 → 響應結果。核心在於 **「請求-響應」協議與通信通道 (Socket) 的建立**。

協議選擇:TCP vs UDP

特性TCP (Socket/ServerSocket)UDP (DatagramSocket)
連接性面向連接、三次握手無連接、數據報
可靠性有序、無丟失、無重複、流量控制不可靠、無序、可能丟包
適用場景HTTP、RPC、數據庫、文件傳輸、即時通訊核心視頻流、DNS、SNMP、廣播、高併發非關鍵數據
Java 類Socket, ServerSocketDatagramSocket, DatagramPacket

**本文聚焦 TCP Socket (流式套接字)。**

IP 地址與端口:網絡身份證

  • IPv4:32 位,點分十進制 (192.168.1.100)。
  • IPv6:128 位,冒號十六進制 (::1, fe80::1)。
  • 端口 (0-65535):0-1023 系統保留 (HTTP 80, HTTPS 443, SSH 22, MySQL 3306),1024-49151 註冊,49152-65535 動態/私有。
  • DNS:域名 → IP 解析,InetAddress.getByName("example.com")。

核心類:Socket 與 ServerSocket


// 客戶端
Socket socket = new Socket("host", port);
InputStream in = socket.getInputStream();   // 讀取響應
OutputStream out = socket.getOutputStream(); // 發送請求

// 服務端
ServerSocket server = new ServerSocket(port);
while (true) {
    Socket client = server.accept(); // 阻塞等待連接
    // 處理 client...
}

實戰 1:簡單文件下載服務 (單線程阻塞)

客戶端


public class FileClient {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket("localhost", 1001);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {

            out.println("RemoteFileServer.java"); // 請求文件名
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

服務端


public class FileServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(1001)) {
            System.out.println("Server started on 1001");
            while (true) {
                try (Socket client = server.accept();
                     BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                     PrintWriter out = new PrintWriter(client.getOutputStream(), true);
                     BufferedReader fileIn = new BufferedReader(new FileReader(in.readLine()))) {

                    String line;
                    while ((line = fileIn.readLine()) != null) {
                        out.println(line);
                    }
                } catch (IOException e) {
                    System.err.println("Client handling error: " + e);
                }
            }
        }
    }
}

實戰 2:多線程服務端 (一連接一線程)


public class ThreadedFileServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(1001, 50)) { // backlog=50
            while (true) {
                Socket client = server.accept();
                new Thread(new ClientHandler(client)).start();
            }
        }
    }

    static class ClientHandler implements Runnable {
        private final Socket socket;
        ClientHandler(Socket socket) { this.socket = socket; }

        public void run() {
            try (Socket s = socket;
                 BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                 PrintWriter out = new PrintWriter(s.getOutputStream(), true);
                 BufferedReader fileIn = new BufferedReader(new FileReader(in.readLine()))) {

                String line;
                while ((line = fileIn.readLine()) != null) out.println(line);
            } catch (IOException e) {
                System.err.println("Handler error: " + e);
            }
        }
    }
}

缺點:線程創建/銷毀開銷大、無上限易導致 OOM、上下文切換頻繁。

實戰 3:線程池 + 隊列 (生產級模型)


public class PooledFileServer {
    private static final ExecutorService POOL = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(1001)) {
            while (true) {
                Socket client = server.accept();
                POOL.execute(new ClientHandler(client)); // 復用線程
            }
        }
    }
    // ClientHandler 同多線程版
}

優化點:固定線程數、隊列緩衝突發、拒絕策略 (CallerRunsPolicy/DiscardOldestPolicy)。

進階:NIO 非阻塞 I/O (Java 1.4+)

核心組件

  • Channel:SocketChannel、ServerSocketChannel、FileChannel — 雙向、可非阻塞。
  • Buffer:ByteBuffer (位置/限制/容量) — 數據容器。
  • Selector:單線程監控多 Channel 就緒事件 (OP_ACCEPT, OP_READ, OP_WRITE, OP_CONNECT) — **Reactor 模式**核心。

NIO 服務端骨架


public class NioServer {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress(1001));
        server.configureBlocking(false);
        server.register(selector, SelectionKey.OP_ACCEPT);

        while (selector.select() > 0) {
            for (SelectionKey key : selector.selectedKeys()) {
                selector.selectedKeys().remove(key);
                if (key.isAcceptable()) accept(key);
                else if (key.isReadable()) read(key);
                else if (key.isWritable()) write(key);
            }
        }
    }
    // accept/read/write 實現略...
}

優勢:單線程支撐萬級連接 (C10K)、無線程切換、內存可控。Netty、Mina、gRPC、Jetty、Undertow** 均基於 NIO 構建。

實戰要點總結

場景推薦模型關鍵注意
低併發、簡單交互BIO 線程池超時設置、資源關閉
高併發、長連接 (IM、推送)NIO (Netty)粘包/拆包、心跳、背壓
文件傳輸、大數據流NIO FileChannel + Mmap / Zero-CopytransferTo/transferFrom
微服務 RPCgRPC (HTTP/2 + Protobuf) / Dubbo (Netty)序列化、負載均衡、熔斷

常見坑與最佳實踐

  • 粘包/拆包:TCP 無邊界,必須自定義協議 (定長、分隔符、長度前綴、TLV)。
  • 半包讀寫:read() 可能不足請求長度,需循環讀取直到滿足協議長度。
  • 優雅關閉:socket.shutdownOutput() 發送 FIN,對端讀到 -1 關閉輸入,雙向關閉。
  • 超時控制:socket.setSoTimeout(ms) (讀超時)、selector.select(timeout)、連接空閒檢測。
  • 緩衝區大小:socket.setSendBufferSize()/setReceiveBufferSize()、ByteBuffer.allocateDirect() (堆外內存、零拷貝)。
  • 安全:SSLSocketFactory / SSLServerSocketFactory 啟用 TLS、雙向認證。

總結

Java Socket 從 BIO 到 NIO,再到 Netty/gRPC 等高性能框架,核心始終是 **「通信協議設計 + I/O 模型選擇 + 併發控制 + 資源管理」**。理解 TCP 流特性、掌握 Reactor 模式、熟悉主流框架原理,是構建高性能、穩健網絡應用的必經之路。**現代新項目首選 Netty/gRPC,避免手寫 NIO;維護舊系統時,線程池 + BIO 仍是性價比最高的選擇。**

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