Java NIO之通道
- 通道
- 通道基礎(chǔ)
- 通道打開
- 通道使用
- 通道關(guān)閉
- Scatter/Gather
- 文件通道
- 文件通道代碼示例
- Socket通道
- Socket通道代碼示例
- 總結(jié)
- 通道基礎(chǔ)
通道
channel用于字節(jié)緩沖區(qū)和位于通道另一側(cè)的實體(通常是一個文件或套接字)之間有效的傳輸數(shù)據(jù)。
通道時一種途徑,通過這種途徑,可以用最小的總開銷來訪問操作系統(tǒng)本身的IO服務(wù),緩沖區(qū)則是通道內(nèi)部用于發(fā)送和接受數(shù)據(jù)的斷點。
通道基礎(chǔ)
頂層接口Channel,次級接口WritableByteChannel、ReadableByteChannel、InterruptibleChannel等。描述通道行為的接口在java.nio.channels包中定義,具體的通道實現(xiàn)都是從java.nio.channels.spi中的類引申來的。
通道打開
IO可以分為廣義的兩大類:File IO和Stream IO,對應(yīng)File通道和Socket通道。體現(xiàn)在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();//輸出標(biāo)記flag.put((byte)'-').put((byte)'-').put((byte)'-').put((byte) '>');flag.flip();dest.write(flag);dest.write(byteBuffer);flag.clear();byteBuffer.compact();}byteBuffer.flip();//確保緩沖區(qū)排干凈while (byteBuffer.hasRemaining()) {flag.putChar('-').putChar('-').putChar('-');flag.flip();dest.write(byteBuffer);flag.clear();}}測試輸入輸出如下:
通道關(guān)閉
與緩沖區(qū)不同,通道不能重復(fù)利用,打開通道即代表與一個特定的IO服務(wù)的特定鏈接并封裝該鏈接的狀態(tài),通道關(guān)閉時,連接丟失,通道不在連接任何東西。
調(diào)用close方法時,可能導(dǎo)致線程暫時阻塞,關(guān)閉的通道上調(diào)用close方法不會產(chǎn)生任何操作,只會立即返回。可以通過isOpen方法判斷通道狀態(tài)。
如果一個線程被中斷,那么這個線程訪問的通道將立即關(guān)閉,這也是為程序健壯性而采用的一種權(quán)衡。
Scatter/Gather
在多個緩沖區(qū)實現(xiàn)一個簡單的IO操作:
對于write,數(shù)據(jù)是從幾個緩沖區(qū)按順序抽取(gather)并沿著通道發(fā)送。該gather過程,好比全部緩沖區(qū)內(nèi)容被連接起來,并在發(fā)送前存放到一個大的緩沖區(qū)。
對于read,從通道讀取的數(shù)據(jù)會被按順序散布(scatter)到多個緩沖區(qū),將每個緩沖區(qū)填滿直至通道中的數(shù)據(jù)或緩沖區(qū)的空間被消耗完。
接口定義如下, 其中read和write入?yún)rBuffer數(shù)組:
文件通道
具體來講FileChannel,接口如下:
public abstract class FileChannelextends AbstractInterruptibleChannelimplements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannelFileChannel 對象是線程安全(thread-safe)的.
對于文件IO,最強大之處在于異步IO,它允許一個進程可以從操作系統(tǒng)請求一個或多個IO操作而不必等待這些操作完成。
文件通道代碼示例
- 將緩沖區(qū)數(shù)據(jù),通過文件channel寫入文件
- 通過文件channel,將文件中的數(shù)據(jù)讀入緩沖區(qū)
Socket通道
新的Socket通道類可以運行非阻塞模式,并且是可選擇的。借助新的NIO類,一個或幾個線程可以管理成百上千的活動socket連接,并且只有很少的性能順勢。
全部 socket 通道類(DatagramChannel、SocketChannel 和 ServerSocketChannel)都是由位于java.nio.channels.spi 包中的AbstractSelectableChannel引申而來。
DatagramChannel 和 SocketChannel 實現(xiàn)定義讀和寫功能的接口而 ServerSocketChannel 不實現(xiàn)。ServerSocketChannel 負(fù)責(zé)監(jiān)聽傳入的連接和創(chuàng)建新的SocketChannel 對象,它本身從不傳 輸數(shù)據(jù)。
Socket通道代碼示例
啟動一個ServerSocketChannel,監(jiān)聽8001端口,非阻塞模式。啟動10個SocketChannel線程向ServerSocketChannel寫數(shù)據(jù)。
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();}}}運行結(jié)果如下:
補充下:
ServerSocketChannel監(jiān)聽的是8001端口,你可以在瀏覽器,輸入:http://localhost:8001/helloworld,你會發(fā)現(xiàn)你的ServerSocketChannel也是可以收到數(shù)據(jù)了,這也web服務(wù)器處理的基礎(chǔ)了。
總結(jié)
以上,了解了基本的通道操作,文件通道和socket通道的使用示例,我覺得點個贊,不過分=。=
以上所有代碼示例,可以fork這里:github
謝謝
轉(zhuǎn)載于:https://www.cnblogs.com/lknny/p/9096212.html
總結(jié)
以上是生活随笔為你收集整理的Java NIO之通道的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 预留信息不完整是怎么回事
- 下一篇: Java知识点梳理——继承