Java NIO之通道
- 通道
- 通道基礎
- 通道打開
- 通道使用
- 通道關閉
- Scatter/Gather
- 文件通道
- 文件通道代碼示例
- Socket通道
- Socket通道代碼示例
- 總結
- 通道基礎
通道
channel用于字節緩沖區和位于通道另一側的實體(通常是一個文件或套接字)之間有效的傳輸數據。
通道時一種途徑,通過這種途徑,可以用最小的總開銷來訪問操作系統本身的IO服務,緩沖區則是通道內部用于發送和接受數據的斷點。
通道基礎
頂層接口Channel,次級接口WritableByteChannel、ReadableByteChannel、InterruptibleChannel等。描述通道行為的接口在java.nio.channels包中定義,具體的通道實現都是從java.nio.channels.spi中的類引申來的。
通道打開
IO可以分為廣義的兩大類:File IO和Stream IO,對應File通道和Socket通道。體現在FileChannel類和三個socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel。
代碼如下:
通道使用
利用通道,從控制臺接收輸入,并在控制臺打印出接收的輸入。代碼如下:
public static void main(String[] args) throws IOException {//一個讀通道,一個寫通道ReadableByteChannel source = Channels.newChannel(System.in);WritableByteChannel dest = Channels.newChannel(System.out);channelCopy(source,dest);source.close();dest.close();}private static void channelCopy(ReadableByteChannel source, WritableByteChannel dest) throws IOException{ByteBuffer byteBuffer = ByteBuffer.allocate(16 * 1024);ByteBuffer flag = ByteBuffer.allocate(4);while (source.read(byteBuffer) != -1) {byteBuffer.flip();//輸出標記flag.put((byte)'-').put((byte)'-').put((byte)'-').put((byte) '>');flag.flip();dest.write(flag);dest.write(byteBuffer);flag.clear();byteBuffer.compact();}byteBuffer.flip();//確保緩沖區排干凈while (byteBuffer.hasRemaining()) {flag.putChar('-').putChar('-').putChar('-');flag.flip();dest.write(byteBuffer);flag.clear();}}測試輸入輸出如下:
通道關閉
與緩沖區不同,通道不能重復利用,打開通道即代表與一個特定的IO服務的特定鏈接并封裝該鏈接的狀態,通道關閉時,連接丟失,通道不在連接任何東西。
調用close方法時,可能導致線程暫時阻塞,關閉的通道上調用close方法不會產生任何操作,只會立即返回。可以通過isOpen方法判斷通道狀態。
如果一個線程被中斷,那么這個線程訪問的通道將立即關閉,這也是為程序健壯性而采用的一種權衡。
Scatter/Gather
在多個緩沖區實現一個簡單的IO操作:
對于write,數據是從幾個緩沖區按順序抽取(gather)并沿著通道發送。該gather過程,好比全部緩沖區內容被連接起來,并在發送前存放到一個大的緩沖區。
對于read,從通道讀取的數據會被按順序散布(scatter)到多個緩沖區,將每個緩沖區填滿直至通道中的數據或緩沖區的空間被消耗完。
接口定義如下, 其中read和write入參時Buffer數組:
文件通道
具體來講FileChannel,接口如下:
public abstract class FileChannelextends AbstractInterruptibleChannelimplements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannelFileChannel 對象是線程安全(thread-safe)的.
對于文件IO,最強大之處在于異步IO,它允許一個進程可以從操作系統請求一個或多個IO操作而不必等待這些操作完成。
文件通道代碼示例
- 將緩沖區數據,通過文件channel寫入文件
- 通過文件channel,將文件中的數據讀入緩沖區
Socket通道
新的Socket通道類可以運行非阻塞模式,并且是可選擇的。借助新的NIO類,一個或幾個線程可以管理成百上千的活動socket連接,并且只有很少的性能順勢。
全部 socket 通道類(DatagramChannel、SocketChannel 和 ServerSocketChannel)都是由位于java.nio.channels.spi 包中的AbstractSelectableChannel引申而來。
DatagramChannel 和 SocketChannel 實現定義讀和寫功能的接口而 ServerSocketChannel 不實現。ServerSocketChannel 負責監聽傳入的連接和創建新的SocketChannel 對象,它本身從不傳 輸數據。
Socket通道代碼示例
啟動一個ServerSocketChannel,監聽8001端口,非阻塞模式。啟動10個SocketChannel線程向ServerSocketChannel寫數據。
ServerSocketChannel代碼如下:
啟動10個SocketCHannel代碼如下:
private static final int port = 8001;public static void main(String[] args) {for (int i=0;i<10;i++) {new SocketChannelImpl(port,i).start();}}private static class SocketChannelImpl extends Thread {private int count = 0;private int port;public SocketChannelImpl(int port,int count){this.port = port;this.count = count;}@Overridepublic void run() {try {SocketChannel socketChannel = SocketChannel.open();/*非阻塞*/socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress(port));for (;!socketChannel.finishConnect();) {System.out.println("connectting....");Thread.sleep(50);}ByteBuffer byteBuffer = ByteBuffer.allocate(1024);String content = "hello, i am client--------->" + count;byteBuffer.put(content.getBytes());byteBuffer.flip();socketChannel.write(byteBuffer);byteBuffer.clear();socketChannel.close();} catch (Exception e) {e.printStackTrace();}}}運行結果如下:
補充下:
ServerSocketChannel監聽的是8001端口,你可以在瀏覽器,輸入:http://localhost:8001/helloworld,你會發現你的ServerSocketChannel也是可以收到數據了,這也web服務器處理的基礎了。
總結
以上,了解了基本的通道操作,文件通道和socket通道的使用示例,我覺得點個贊,不過分=。=
以上所有代碼示例,可以fork這里:github
謝謝
轉載于:https://www.cnblogs.com/lknny/p/9096212.html
總結
以上是生活随笔為你收集整理的Java NIO之通道的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 预留信息不完整是怎么回事
- 下一篇: Java知识点梳理——继承