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

Java Socket 通信:BufferedReader readLine() 阻塞原因與 flush()/close() 差異解析

     編輯:程式設計綜合問答

服務端 os.write("北京".getBytes()); os.flush(); 客戶端 BufferedReader.readLine() 一直阻塞;改為 os.close() 客戶端才能讀到數據。根本原因在於 readLine() 依賴換行符作為終止標誌。

核心機制

  • BufferedReader.readLine():讀取字符直到遇到 \n、\r 或 \r\n,返回不含換行符的字符串。**若流未關閉且無換行符,會無限阻塞等待。**
  • os.flush():僅刷新 Java 層緩衝區到作業系統發送緩衝區,**不發送任何協議級終止標誌**。
  • os.close():關閉 Socket 輸出流,發送 TCP FIN 包,導致對端 read() 返回 -1 (EOF),readLine() 因而返回已讀內容(即使無換行符)。

正確解決方案(三選一)

  1. 發送端主動加換行符(推薦):
    os.write("北京\n".getBytes()); // 或 "\r\n"
    os.flush();
    
  2. 接收端不使用 readLine(),改用定長/分隔符協議:
    byte[] buf = new byte[1024];
    int len = ins.read(buf); // 阻塞直到有數據或 EOF
    String msg = new String(buf, 0, len, "UTF-8");
    
  3. 短連接模式: 發送完調用 socket.shutdownOutput()(半關閉),接收端讀到 EOF 返回。但無法復用連接。

最佳實踐建議

  • **應用層協議必須定義消息邊界**:換行符、長度前綴、特殊分隔符、序列化框架。
  • 長連接場景**禁用 readLine()**,改用 DataInputStream.readInt() 讀長度 + readFully() 讀體,或 Netty/Mina 等框架處理半包/粘包。
  • 調試時用 Wireshark 抓包確認數據包內容與 TCP 狀態,比代碼推測更直觀。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved