NIO-Channel簡介

2021-02-15 跳動的數據

一個channel(通道)表示一個連接,一個channel可以表示一個底層的文件描述符,比如有硬體設備、文件、網絡套接字,或者是執行IO的讀寫操作。在Java NIO中有不同的Channel實現。


這裡簡單介紹主要Channel的使用,如果想詳細的了解,可以像下圖一樣了解整體的設計結構。




有哪些Channel實現


NIO中主要的channel實現如下:

FileChannel:文件通道,用於文件數據的讀寫。

DatagramChannel:數據報通道,可以通過UDP協議讀取網絡中的數據。

SocketChannel:套接字通道,用於Socket套接字TCP網絡連接的數據讀寫。

ServerSocketChannel:伺服器監聽通道,可以監聽TCP連接請求,對每個監聽進來的連接都創建一個SocketChannel套接字通道。


FileChannel示例


public static void fileChannelTest() {   RandomAccessFile raf = null;   FileChannel fileChannel = null;   try {       raf = new RandomAccessFile("/usr/local/tools/a.txt", "rw");       //創建一個RandomAccessFile對象,傳入一個文件路徑,支持讀寫模式
//獲取文件通道 fileChannel = raf.getChannel();
//創建字節緩衝區,用於讀取數據和寫入數據 ByteBuffer buffer = ByteBuffer.allocate(48);
//從文件讀取輸出控制臺 while (fileChannel.read(buffer) != -1) { buffer.flip(); String str = new String(buffer.array(), buffer.position(), buffer.limit(), "utf-8"); System.err.print(str); buffer.clear(); }
//寫數據 buffer.put("\n新信息!!!".getBytes("UTF-8")); //切換讀模式 buffer.flip(); //通道寫數據 fileChannel.write(buffer);
} catch (Exception e) { e.printStackTrace(); } finally { try { raf.close(); fileChannel.close(); } catch (IOException e) { e.printStackTrace(); } }}


要注意的是在ByteBuffer的模式切換,新創建的ByteBuffer模式是寫模式。如果這時想從通道讀數據,可以作為參數傳進去,從通道讀取的數據寫入到ByteBuffer。


在往通道寫數據時,需要將ByteBuffer切換為讀模式,作為參數傳入輸出Channel,從ByteBuffer讀取數據寫入輸出Channel。


SocketChannel套接字通道


NIO中的SocketChannel是一個連接到TCP網絡套接字的通道。可以通過以下2種方式創建SocketChannel,打開一個SocketChannel並連接到網際網路上的某臺伺服器,一個新連接到達ServerSocketChannel時,會創建一個SocketChannel。


ServerSocketChannel用於伺服器端,SocketChannel同時用於服務端和客戶端,換句話說,對應一個連接,兩端都有一個負責傳輸的SocketChannel傳輸通道。


SocketChannel支持阻塞和非阻塞模式,通過socketChannel.configureBlocking(true)設置,默認是非阻塞的。在阻塞模式下, Socket Channel通道的 connect、read、 write操作,都是同步的和阻塞式的,在效率上與Java舊的OIO的面向流的阻塞式讀寫操作相同。


Java NIO中的 ServerSocketChannel 是一個可以監聽新進來的TCP連接的通道, 就像標準IO中的ServerSocket一樣。ServerSocketChannel類在 java.nio.channels包中。


創建連接通道


//獲得一個通道SocketChannel socketChannel = SocketChannel.open();//設置非阻塞模式socketChannel.configureBlocking(true);//發起連接socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888));
//在阻塞模式下可能還沒有建立連接,一直不挺的自旋while (!socketChannel.finishConnect()) {
}


SocketChannel寫數據


String newData = "abcde" + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);buf.put(newData.getBytes());
buf.flip();while(buf.hasRemaining()) { socketChannel.write(buf);}


SocketChannel讀取數據


ByteBuffer buf1 = ByteBuffer.allocate(48);int bytesRead = socketChannel.read(buf1);

讀取是異步的,因此我們必須檢查read的返回值,以便判斷當前是否讀取到了數據。read()方法的返回值,是讀取的字節數。如果返回-1,那麼表示讀取到對方的輸出結束標誌,對方已經輸出結束,準備關閉連接。實際上在讀取數據時還是需要Selector選擇器。



關閉SocketChannel


在關閉 Socketchannel傳輸通道前,如果傳輸通道用來寫入數據,建議調用一次 shutdownOutput終止輸出方法,向對方發送一個輸出的結束標誌-1。然後調用 socketchannel.close()方法,關閉套接字連接。

//輸出結束標識socketChannel.shutdownOutput();//關閉套接字socketChannel.close();

DatagramChannel數據報通道

NIO中的DatagramChannel是一個能收發UDP包的通道。因為UDP是無連接的網絡協議,所以不能像其它通道那樣讀取和寫入。它發送和接收的是數據包。使用 DatagramChannel數據報通道來處理UDP協議的數據傳輸。


打開通道


打開的 DatagramChannel可以在UDP埠9000上接收數據包

DatagramChannel datagramChannel = DatagramChannel.open();datagramChannel.configureBlocking(false);datagramChannel.socket().bind(new InetSocketAddress(9000));


從數據報通道讀取數據


可以從DatagramChannel通道讀取數據,和前面的 Socketchannel的讀取方式不同,不是調用read方法,而是調用receive( Byte Bufferbuf)方法將數據從 Datagramchannel讀入,再寫入到ByteBuffer緩衝區中。

ByteBuffer buf2 = ByteBuffer.allocate(48);buf2.clear();datagramChannel.receive(buf2);


寫數據到數據報通道


向 DatagramChannel發送數據,和向 SocketChannel通道發送數據的方法也是不同的。這裡不是調用 write方法,而是調用send方法。

String strData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf3 = ByteBuffer.allocate(48);buf3.put(newData.getBytes());buf3.flip();datagramChannel.send(buf, new InetSocketAddress("127.0.0.1", 9000));

UDP是面向非連接的協議,因此,在調用send方法發送數據的時候,需要指定接收方的地址(IP和埠)



參考資料

http://ifeve.com/datagram-channel/

http://ifeve.com/socket-channel/

相關焦點

  • Java NIO:Buffer、Channel 和 Selector
    (點擊上方公眾號,可快速關注)來源:JavaDoop ,javadoop.com/post/java-nio
  • Java NIO詳解
    TCP協議相關的數據傳輸通道Pipe.SinkChannel、Pipe.SourceChannel //線程通信管道傳輸數據Channel常用方法public static void main(String[] args) throws IOException {  File srcFile = new File("nio-a.txt
  • 攻破JAVA NIO技術壁壘
    NIO的channel抽象的一個重要特徵就是可以通過配置它的阻塞行為,以實現非阻塞式的信道。channel.configureBlocking(false)在非阻塞式信道上調用一個方法總是會立即返回。這種調用的返回值指示了所請求的操作完成的程度。
  • Java NIO Buffer【MappedByteBuffer】概述與FileChannel的聯繫
    * 線程不安全,可以鏈式調用 * b.flip().position(23).limit(42); * */代碼演示import java.nio.ByteBuffer
  • Java Web安全 || Java基礎 · Java IO/NIO多種讀寫文件方式
    FileSystemProvider讀取文件內容示例:package com.anbai.sec.filesystem;import java.io.IOException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths
  • Java文件的簡單讀寫、隨機讀寫、NIO讀寫與使用MappedByteBuffer讀寫
    public class FileChannelStu{ public void testFileLock(){ FileChannel channel = this.channel; FileLock fileLock = null; try { fileLock = channel.lock
  • 蔚來汽車發布英文品牌及首款產品 現已啟用域名nio.com
    相關域名nio.com早已被蔚來汽車啟用。  據了解,蔚來汽車的英文品牌名稱「NIO」取意「A New Day(新的一天)」,代表著蔚來汽車追求美好明天和蔚藍天空、為用戶創造愉悅生活方式的願景。3字母域名nio.com恰好與其品牌相呼應,在方便用戶訪問的同時還能起到品牌宣傳的效果。
  • Golang 入門筆記 - Channel
    大家應該都知道,goroutine 是通過 channel 實現相互通信的。channel 確保 goroutine 和主線程時間可以相互通信。在這篇文章中,將會與大家討論如何創建 channel 和實現數據共享。簡單介紹下 channelchannel 給編程帶來了很大的靈活性,並解決了涉及並發的各種問題。
  • golang開發:channel使用
    channel主要是用於多個goroutine之間通信channel語法channel是引用類型,需要實用make來創建channel
  • 走進Golang之Channel的使用
    channel 是什麼Don't communicate by sharing memory, share memory by communicating.相信寫過 Go 的同學都知道這句名言,可以說 channel 就是後邊這句話的具體實現。我們來看一下到底 channel 是什麼?
  • 走進Golang之Channel的數據結構
    上篇文章講了 channel 的基本使用,講了一些使用時需要注意的事項,本文將重點介紹 channel 中的兩個數據結構:循環隊列 與 雙端鍊表 。對於有緩存的 channel 可以採用 循環隊列 來管理多個消息。
  • 【Golang】圖解channel之數據結構
    channel被設計用來實現goroutine間的通信,按照golang的設計思想:以通信的方式共享內存。
  • TV channel suspended for showing porn
    DownloadAuthorities in Southwest China's Chongqing municipality have suspended a local television channel and vowed a thorough investigation
  • channel[V]製作重心北移到上海
    其實,1994年channel[V]的三個啟播點之一就在中國的長城。因此可以說,[V]又回到了自己的發源地。channel[V](中國)今年初新到任的總經理李岱表示:一個名牌的誕生需要市場支持和潮流意識,中國市場已擁有龐大的消費能力,本地人才也完全可以創作出高質量高水準的作品。
  • Golang並發:再也不愁選channel還是選鎖
    在Golang裡,channel也不是萬能的,這是由channel的特性和局限造成的。下面就給大家介紹channel的特點、核心方法和缺點。channel解決並發問題的思路和示例channel的核心是數據流動,關注到並發問題中的數據流動,把流動的數據放到channel中,就能使用channel解決這個並發問題。
  • 一文帶你解密 Go 語言之通道 channel
    channel 共有兩種模式,分別是:雙向和單向;三種表現方式,分別是:聲明雙向通道:chan T、聲明只允許發送的通道:chan <- T、聲明只允許接收的通道:<- chan T。channel 中還分為 「無緩衝 channel」 和 「緩衝 channel」。