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

Java NIO網絡傳輸圖片數據丟失:ByteBuffer翻轉與通道讀寫完整性保證

     編輯:程式設計綜合問答

問題現象

使用 `ByteBuffer` 發送圖片對象,接收端數據不完整、圖片損壞、丟失大量數據。

核心原因

ByteBuffer 讀寫模式切換(flip/rewind/compact)使用不當,導致:

  • 發送端未 `flip()` 直接 `write()` → 從 position=0 寫入 capacity 大小,包含未初始化垃圾數據
  • 接收端未循環 `read()` 直到 `remaining()==0` → 單次讀取不足,數據截斷
  • 未處理「黏包/半包」:TCP 流無邊界,應用層需自定義協議(長度前綴/分隔符)

正確收發模式

發送端

ByteBuffer buffer = ByteBuffer.allocate(1024 * 64); // 64KB
// 1. 序列化圖片到 buffer(put 操作)
buffer.put(imageBytes); // position 推進
// 2. **關鍵:翻轉準備讀取/發送**
buffer.flip(); // limit=position, position=0
// 3. 循環發送直到 buffer 無剩餘
while (buffer.hasRemaining()) {
    int written = channel.write(buffer);
    if (written == 0) {
        // 可選:等待可寫事件(Selector OP_WRITE)
    }
}

接收端

ByteBuffer buffer = ByteBuffer.allocate(1024 * 64);
// 1. 讀取長度前綴(假設協議:前4字節為圖片長度)
ByteBuffer header = ByteBuffer.allocate(4);
while (header.hasRemaining()) channel.read(header);
header.flip();
int length = header.getInt();

// 2. 分配精確大小 buffer
ByteBuffer body = ByteBuffer.allocate(length);
// 3. 循環讀取直到填滿
while (body.hasRemaining()) {
    int read = channel.read(body);
    if (read == -1) throw new EOFException("連接斷開");
}
body.flip(); // 準備讀取數據
byte[] imageData = new byte[length];
body.get(imageData); // 完整圖片數據

關鍵 API 速查

完整性保證清單

  1. 協議定長:長度前綴(4/8字節)+ 數據體
  2. 發送端:`put` → `flip` → 循環 `write` 直到 `!hasRemaining()`
  3. 接收端:讀長度 → 分配Buffer → 循環 `read` 直到 `!hasRemaining()`
  4. 異常處理:`read/write` 返回 0 註冊 `OP_READ/OP_WRITE`,返回 -1 關閉連接
  5. 大文件:考慮 `FileChannel.transferTo/From` 零拷貝或分塊傳輸
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法作用位置變化
put()寫入數據position += n
flip()切換為讀模式limit=position, position=0
rewind()重讀(不改limit)position=0
compact()未讀數據移至開頭未讀數據前移, position=剩餘
clear()重置寫模式position=0, limit=capacity
hasRemaining()是否有剩餘可讀/寫position < limit