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

Java Socket 雙向通信實戰:客戶端與服務端完整代碼示例

     編輯:Java 綜合教學

Java Socket 雙向通信實戰

基於 TCP Socket 實現客戶端發送請求、服務端處理後主動回覆的完整流程。關鍵點在於雙方正確關閉輸出流(shutdownOutput())以觸發對端 readLine() 返回 null 結束讀取循環。

一、服務端代碼

package com.socket.demo;

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

public class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("----------------服務端啟動,監聽 8888 端口----------------");
            Socket socket = serverSocket.accept();
            System.out.println("客戶端連接:" + socket.getInetAddress());

            // 1. 讀取請求
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("收到請求:" + line);
                }
            }

            // 關閉輸入流,表示讀取完畢
            socket.shutdownInput();

            // 2. 發送回覆
            try (PrintWriter writer = new PrintWriter(
                    new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true)) {
                writer.println("服務端已收到您的消息,處理完成。");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、客戶端代碼

package com.socket.demo;

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

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("127.0.0.1", 8888)) {
            // 1. 發送請求
            try (PrintWriter writer = new PrintWriter(
                    new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true)) {
                writer.println("客戶端請求:你好,服務端!");
            }

            // 關鍵:關閉輸出流,通知服務端請求結束
            socket.shutdownOutput();

            // 2. 讀取回覆
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("服務端回覆:" + line);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、關鍵點解析

操作作用缺失後果
socket.shutdownOutput() (Client)發送 FIN 包,服務端 readLine() 返回 null 跳出循環服務端永久阻塞在讀取循環
socket.shutdownInput() (Server)發送 FIN 包,客戶端 readLine() 返回 null 跳出循環客戶端永久阻塞在讀取循環
PrintWriter(..., true)啟用自動 flush,println 後自動發送需手動 flush(),否則數據滯留緩衝區
try-with-resources自動關閉流與 Socket,釋放文件描述符資源洩漏,端口佔用

四、常見坑點

  1. 忘記 shutdownOutput:導致對端 readLine() 永不返回 null,線程掛起。
  2. 編碼不一致:雙方必須約定字符集(建議 UTF-8),否則中文亂碼。
  3. 單線程阻塞:示例為單連接阻塞模型,生產環境需引入線程池或 NIO 多路複用(Netty/Mina)。

五、進階擴展建議

  • 應用層協議:定義消息頭(長度/類型/序列號)解決粘包/半包。
  • 心跳機制:檢測長連接存活。
  • 優雅關閉:雙向 shutdownOutput + 等待對端 ACK 後關閉 Socket。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved