[TOC]
> 在開始之前,我覺得有必要充分理解一下緩沖區的作用及使用方法。
## 一、緩沖區基礎
在NIO技術的緩沖區中,存在4個核心技術點,分別是:
?capacity(容量)
?limit(限制)
?position(位置)
?mark(標記)
這4個技術點之間值的大小關系如下:0≤mark≤position≤limit≤capacity。
由于ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer是抽象類,wrap()就相當于創建這些緩沖區的工廠方法。最終對應的類型分別為`java.io.HeapByteBuffer`、`java.io.HeapCharBuffer`、`java.io.HeapDoubleBuffer`等。
### limit
限制(limit)代表第一個不應該讀取或寫入元素的index,緩沖區的limit不能為負,并且limit不能大于其capacity。如果position大于新的limit,則將position設置為新的limit。如果mark已定義且大于新的limit,則丟棄該mark。

```java
public class BufferTest {
@Test
public void bufferLimitTest(){
char[] charArray = new char[]{'a','b','c','d','e'};
CharBuffer buffer = CharBuffer.wrap(charArray);
System.out.println("A capacity()=" + buffer.capacity() + ",limit="+buffer.limit());
buffer.limit(3);
System.out.println("B capacity()=" + buffer.capacity() + ",limit="+buffer.limit());
buffer.put(0,'o');
buffer.put(1,'p');
buffer.put(2,'q');
buffer.put(3,'r');//index == 3,第一個不可讀不可寫的索引
buffer.put(4,'s');
buffer.put(5,'t');
buffer.put(6,'u');
}
}
```
### position(位置)
什么是位置呢?它代表“下一個”要讀取或寫入元素的index(索引),緩沖區的position(位置)不能為負,并且position不能大于其limit。如果mark已定義且大于新的position,則丟棄該mark。

```java
@Test
public void bufferLimitTest(){
char[] charArray = new char[]{'a','b','c','d','e'};
CharBuffer buffer = CharBuffer.wrap(charArray);
System.out.println("A capacity()=" + buffer.capacity() + ",limit="+buffer.limit()+ ",position="+buffer.position());
buffer.limit(3);
System.out.println("B capacity()=" + buffer.capacity() + ",limit="+buffer.limit() + ",position="+buffer.position());
buffer.put(0,'o');
buffer.put(1,'p');
buffer.put(2,'q');
buffer.put(3,'r');//index == 3,第一個不可讀不可寫的索引
buffer.put(4,'s');
buffer.put(5,'t');
buffer.put(6,'u');
}
```
> 運行結果如下:
> A capacity()=5,limit=5,position=0
> B capacity()=5,limit=5,position=2
> a
> b
> Z
> d
> e
### mark(標記)
標記有什么作用呢?緩沖區的標記是一個索引,在調用reset()方法時,會將緩沖區的position位置重置為該索引。標記(mark)并不是必需的。定義mark時,不能將其定義為負數,并且不能讓它大于position。
- 如果定義了mark,則在將position或limit調整為小于該mark的值時,該mark被丟棄,丟棄后mark的值是-1。
- 如果未定義mark,那么調用reset()方法將導致拋出`InvalidMarkException`異常。
簡而言之,buffer的reset()方法,可以根據mark()的位置,把位置重置為mark()調用時的位置。
其他的一些關系:
- 如果position大于新的limit,則position的值就是新limit的值。
## 二、非直接緩沖區和直接緩沖區
### 非直接緩沖區

通過ByteBuffer向硬盤存取數據時是需要將數據暫存在JVM的中間緩沖區,如果有頻繁操作數據的情況發生,則在每次操作時都會將數據暫存在JVM的中間緩沖區,再交給ByteBuffer處理,這樣做就大大降低軟件對數據的吞吐量,提高內存占有率,造成軟件運行效率降低,這就是非直接緩沖區保存數據的過程,所以非直接緩沖區的這個弊端就由直接緩沖區解決了。
### 直接緩沖區

- 第一章 開篇寄語
- 1-1 技術選型要點
- 1-2 認識905.4王國的交流規范
- 1-3 聯系作者
- 第二章 Socket編程的基礎知識
- 2-1 Socket家族的基石
- 2-2 byte數組基礎
- 2-3 緩沖區基礎
- 2-4 NIO Socket通訊的工作原理
- 第三章 905.4規范解讀
- 3-1 基于通道選擇器的Socket長連接及消息讀寫框架
- 3-2 嚴格的信件收發員
- 3-3 負責消息處理的一家子
- 3-4 負責認證的大兒子(AuthWorker)
- 3-5 啞巴老二(PingWoker)
- 3-6 勤奮的定位匯報員老三(LocationReportWorker)
- 3-7 精明的老四(BusinessReportWorker)
- 3-8 數據檢察官——CRC16-CCITT校驗
- 3-11 數據的加密官
- 3-12 頭尾標識轉義
- 第四章 測試方法
- 4-1 測試數據樣例
- 4-2 客戶端鏈路保持功能實現
- 4-3 使用Socket短連接進行功能測試
- 4-4 NIO服務端性能分析
- 4-5 http測試方法(推薦)
- 第五章 從NIO到netty
- 5-1 編程進階——Netty核心基礎
- 5-2 Netty使用常見問題
- 5-3 使用Netty重寫Server端
- 5-4 Netty之鏈路管理
- 5-5 netty堆外內存泄漏如何應對?
- 第六章 統計與監控
- 6-1 Grafana監控面板
- 第七章 售后服務
- 7-1 勘誤與優化
- 7-2 獲取源碼