NIO-Channel



NIO-Channel

目錄

NIO-概覽
NIO-Buffer
NIO-Channel
NIO-Channel接口分析java

前言

原本是想學習Netty的,可是Netty是一個NIO框架,所以在學習netty以前,仍是先梳理一下NIO的知識。經過剖析源碼理解NIO的設計原理。windows

本系列文章針對的是JDK1.8.0.161的源碼。微信

什麼是Channel

通道(Channel)是對原I/O包中的流的模擬。與文件設備I/O交互的全部數據都必須經過一個Channel對象。網絡

上一節咱們提到在NIO中使用緩衝區來存放指定基元的數據,咱們能夠經過Buffer來讀寫數據。
將數據寫入到硬盤時,咱們能夠將字節數據寫入到緩衝區中;若咱們要從硬盤讀取數據,則須要經過通道將數據寫入到緩衝區,而後再從緩衝區讀取數據。框架

通道類型

根據不一樣的使用方式,分爲不一樣的通道。好比咱們須要網絡讀寫,就須要網絡交互的通道。須要文件讀寫就須要文件交互的通道。
NIO實現了Sctp協議、TCP協議、UDP協議以及文件傳輸四種通道,同時還實現了Windows平臺的異步Socket通道以及異步文件通道。dom

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平臺的異步通道socket

類型 通道
TCP協議異步I/O服務端 WindowsAsynchronousServerSocketChannel
TCP協議異步I/O客戶端 WindowsAsynchronousSocketChannel
異步文件讀寫 WindowsAsynchronousFileChannel

另外NIO還實現了一個單向通信管道(Pipe)的功能,經過引入SourceChannelSinkChannel實現,底層實際仍是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源碼單獨分出來說解。

相關文獻

  1. SCTP協議詳解
  2. 史上最強Java NIO入門:擔憂從入門到放棄的,請讀這篇!
  3. Java NIO系列教程

20191127212134.png
微信掃一掃二維碼關注訂閱號傑哥技術分享
出處:http://www.javashuo.com/article/p-pwariqtr-gr.html 做者:傑哥很忙 本文使用「CC BY 4.0」創做共享協議。歡迎轉載,請在明顯位置給出出處及連接。

相關文章
相關標籤/搜索