NIO-Channel
目錄
- NIO-Channel
- 目錄
- 前言
- 什麼是Channel
- 通道型別
- 如何使用
- ServerSocketChannel
- SocketChannel
- FileChannel
- 總結
- 相關文獻
NIO-Channel
目錄
NIO-概覽
NIO-Buffer
NIO-Channel
NIO-Channel原始碼解析
前言
本來是想學習Netty的,但是Netty是一個NIO框架,因此在學習netty之前,還是先梳理一下NIO的知識。通過剖析原始碼理解NIO的設計原理。
本系列文章針對的是JDK1.8.0.161的原始碼。
什麼是Channel
通道(Channel)是對原I/O包中的流的模擬。與檔案裝置I/O互動的所有資料都必須通過一個Channel物件。
上一節我們提到在NIO中使用緩衝區來存放指定基元的資料,我們可以通過Buffer來讀寫資料。
將資料寫入到硬碟時,我們可以將位元組資料寫入到緩衝區中;若我們要從硬碟讀取資料,則需要通過通道將資料寫入到緩衝區,然後再從緩衝區讀取資料。
通道型別
根據不同的使用方式,分為不同的通道。比如我們需要網路讀寫,就需要網路互動的通道。需要檔案讀寫就需要檔案互動的通道。
NIO實現了Sctp協議、TCP協議、UDP協議以及檔案傳輸四種通道,同時還實現了Windows平臺的非同步Socket通道以及非同步檔案通道。
windows平臺的非同步I/O是通過重疊I/O和IOCP(I/O完成埠)實現的,想要了解windows非同步I/O的知識可以看一下我另一篇文章《Windows核心原理-同步IO與非同步IO》
型別 | 通道 |
---|---|
Sctp協議客戶端 | SctpChannel |
Sctp協議多播客戶端 | SctpMultiChannel |
Sctp協議服務端 | SctpServerChannel |
UDP協議 | DatagramChannel |
TCP協議同步I/O服務端 | ServerSocketChannel |
TCP協議同步I/O客戶端 | ServerChannel |
檔案讀寫 | FileChannel |
對於Windows平臺的非同步通道
型別 | 通道 |
---|---|
TCP協議非同步I/O服務端 | WindowsAsynchronousServerSocketChannel |
TCP協議非同步I/O客戶端 | WindowsAsynchronousSocketChannel |
非同步檔案讀寫 | WindowsAsynchronousFileChannel |
另外NIO還實現了一個單向通訊管道(Pipe)的功能,通過引入
SourceChannel
和SinkChannel
實現,底層實際還是Socket通訊。
如何使用
在介紹不同的Channel的實現之前我們先介紹下Channel如何使用。
ServerSocketChannel
以TCP協議為例,我們進行網路收發的時候,首先需要建立一個ServerSocketChannel用於監聽埠。
//建立一個服務端socket通道用於接收連線
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//繫結監聽地址
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
//等待連線
SocketChannel socketChannel = serverSocketChannel.accept();
我們監聽了8080埠。若沒有連線時,執行緒會阻塞在
accept
。
當有收到新的連線建立時,會獲取到SocketChannel,此時我們需要建立一個Buffer用來從Channel中讀取資料。
ByteBuffer buf = ByteBuffer.allocate(1024);
//資料將寫入到buffer中
int length = socketChannel.read(buf);
資料寫入到我們的Buffer中,我們就需要將他們讀出來
buf.flip(); //轉化為可讀模式
byte[] data = new byte[length];
buf.get(data);
將資料從Buffer寫入到Channel時
buf.clear();
byte[] resp = {'O','K'};
buf.put(resp);
buf.flip();//轉換為讀模式
socketChannel.write(buf);
這裡為了方便直接使用原來的Buffer。
SocketChannel
作為客戶端我們需要建立一個SocketChannel。
SocketChannel.open();
client.connect(new InetSocketAddress("127.0.0.1", 6060));
傳送HELLO
給服務端
ByteBuffer buffer = ByteBuffer.allocate(10);
byte[] data = {'H', 'E', 'L', 'L', 'O'};
buffer.put(data);
buffer.flip();//轉換為讀模式
client.write(buffer);
阻塞等待讀取資料
buffer.clear();
client.read(buffer);
buffer.flip();//轉換為讀模式
處理完成,需要關閉釋放連線
//關閉客戶端輸入流
client.socket().shutdownInput();
//關閉客戶端輸出流
client.socket().shutdownOutput();
//關閉客戶端socket時會關閉客戶端channel
client.socket().close();
//關閉客戶端channel,會同時關閉輸入和輸出流。
client.close();
關閉輸出流會發送FIN包,若輸入流未關閉仍然可以繼續接收資料,這就是TCP的半連線。若處理完最後需要確保channel關閉。
FileChannel
FileChannel只能被FileInputStream、FileOutputStream、RandomAccessFile建立
RandomAccessFile
使用RandomAccessFile
建立FileChannel
//第一個引數時檔名,第二個引數是讀寫方式
RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt","rw");
FileChannel channel = randomAccessFile.getChannel();
FileInputStream
使用RandomAccessFile
建立FileChannel
FileInputStream inputStream = new FileInputStream("1.txt");
channel = inputStream.getChannel();
inputStream獲取的FileChannel只能讀
FileOutputStream
使用RandomAccessFile
建立FileChannel
FileOutputStream outputStream = new FileOutputStream("1.txt");
channel = outputStream.getChannel();
inputStream獲取的FileChannel只能寫
關閉FileChannel
關閉FileChannel的方法和關閉SocketChannel方法一樣。
//關閉channel時會關閉檔案
channel.close();
//關閉檔案時會關閉channel
randomAccessFile.close();
//關閉檔案流時會關閉channel
inputStream.close();
//關閉檔案流時會關閉channel
inputStream.close();
總結
由於原始碼解析的篇幅較長,因此將《channel原始碼解析》單獨分出來一篇文章。
相關文獻
- SCTP協議詳解
- 史上最強Java NIO入門:擔心從入門到放棄的,請讀這篇!
- Java NIO系列教程
微信掃一掃二維碼關注訂閱號傑哥技術分享
出處:https://www.cnblogs.com/Jack-Blog/p/12015516.html
作者:傑哥很忙
本文使用「CC BY 4.0」創作共享協議。歡迎轉載,請在明顯位置給出出處及連結。