## 7.3.1 read
在與客戶端建立連接時,會創建客戶端通道NioSocKetChannel,并注冊到`子事件循環`中,由其不斷select()查詢就緒的I/O,然后再針對I/O進行處理。處理讀操作的是NioSocketChannel的unsafe,由NioSocketChannelUnsafe實現,read()在AbstractNioByteChannel$NioByteUnsafe中。其主要的過程比較簡單:
1. 子Channel的創建過程在,其ChannelConfig會創建ByteBufAllocator,用于分配內存,默認的分配器為PooledByteBufAllocator;內存分配的過程比較復雜,在內存管理一節介紹;RecvByteBufAllocator用于計算緩沖區的大小;通過這兩個對象,可以獲取緩沖區byteBuf = allocHandle.allocate(allocator);
2. doReadBytes(byteBuf)中,每次從javaChannel中讀取數據;之后通知pipeline觸發fireChannelRead(byteBuf);結束后判斷是否還有未讀取的數據,如果有則繼續循環讀取。
3. 最后,allocHandle.readComplete();重新計算緩沖區大小并通知pipeline觸發fireChannelReadComplete();
```
do {
byteBuf = allocHandle.allocate(allocator);
allocHandle.lastBytesRead(doReadBytes(byteBuf));
if (allocHandle.lastBytesRead() <= 0) {
byteBuf.release();
byteBuf = null;
close = allocHandle.lastBytesRead() < 0;
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
```
## 7.3.2 write
在Netty使用過程中,一般會在業務邏輯的ChannelInboundHandlerAdapter的channelRead中,調用ctx.write();和ctx.flush()向客戶端發送數據。寫入的邏輯比較簡單:
1. 查找下一個Outbound的Handler,中間可能有一些業務邏輯Handler,最終處理write的是HeadContext,如果需要flush則調用invokeWriteAndFlush,否則調用invokeWrite
2. invokeWrite會調用unsafe的write(msg, promise); 將其加入到outboundBuffer中,這里不會flush通過網絡發送
3. flush()方法,調用unsafe的flush();最終通過javaChannel寫入網絡