1. 程式人生 > >NIO-Channel

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)的功能,通過引入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系列教程


微信掃一掃二維碼關注訂閱號傑哥技術分享
出處:https://www.cnblogs.com/Jack-Blog/p/12015516.html
作者:傑哥很忙
本文使用「CC BY 4.0」創作共享協議。歡迎轉載,請在明顯位置給出出處及連結。