摘要:通常來說所有的的操作都是從開始的一個(gè)類似于一個(gè)和對(duì)比我們可以在同一個(gè)中執(zhí)行讀和寫操作然而同一個(gè)僅僅支持讀或?qū)懣梢援惒降刈x寫而是阻塞的同步讀寫總是從中讀取數(shù)據(jù)或?qū)?shù)據(jù)寫入到中類型有文件操作操作操作操作使用在服務(wù)器端這些通道涵蓋了和網(wǎng)絡(luò)以及文件
Java NIO Channel
通常來說, 所有的 NIO 的 I/O 操作都是從 Channel 開始的. 一個(gè) channel 類似于一個(gè) stream.
java Stream 和 NIO Channel 對(duì)比
我們可以在同一個(gè) Channel 中執(zhí)行讀和寫操作, 然而同一個(gè) Stream 僅僅支持讀或?qū)?
Channel 可以異步地讀寫, 而 Stream 是阻塞的同步讀寫.
Channel 總是從 Buffer 中讀取數(shù)據(jù), 或?qū)?shù)據(jù)寫入到 Buffer 中.
Channel 類型有:
FileChannel, 文件操作
DatagramChannel, UDP 操作
SocketChannel, TCP 操作
ServerSocketChannel, TCP 操作, 使用在服務(wù)器端.
這些通道涵蓋了 UDP 和 TCP網(wǎng)絡(luò) IO以及文件 IO.
基本的 Channel 使用例子:
public static void main( String[] args ) throws Exception { RandomAccessFile aFile = new RandomAccessFile("/Users/xiongyongshun/settings.xml", "rw"); FileChannel inChannel = aFile.getChannel(); ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); while (bytesRead != -1) { buf.flip(); while(buf.hasRemaining()){ System.out.print((char) buf.get()); } buf.clear(); bytesRead = inChannel.read(buf); } aFile.close(); }FileChannel
FileChannel 是操作文件的Channel, 我們可以通過 FileChannel 從一個(gè)文件中讀取數(shù)據(jù), 也可以將數(shù)據(jù)寫入到文件中.
注意, FileChannel 不能設(shè)置為非阻塞模式.
RandomAccessFile aFile = new RandomAccessFile("test.txt", "rw"); FileChannel inChannel = aFile.getChannel();從 FileChannel 中讀取數(shù)據(jù)
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf);寫入數(shù)據(jù)
String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while(buf.hasRemaining()) { channel.write(buf); }關(guān)閉
當(dāng)我們對(duì) FileChannel 的操作完成后, 必須將其關(guān)閉
channel.close();設(shè)置 position
long pos channel.position(); channel.position(pos +123);文件大小
我們可以通過 channel.size()獲取關(guān)聯(lián)到這個(gè) Channel 中的文件的大小. 注意, 這里返回的是文件的大小, 而不是 Channel 中剩余的元素個(gè)數(shù).
截?cái)辔募?/b>channel.truncate(1024);
將文件的大小截?cái)酁?024字節(jié).
強(qiáng)制寫入我們可以強(qiáng)制將緩存的未寫入的數(shù)據(jù)寫入到文件中:
channel.force(true);SocketChannel
SocketChannel 是一個(gè)客戶端用來進(jìn)行 TCP 連接的 Channel.
創(chuàng)建一個(gè) SocketChannel 的方法有兩種:
打開一個(gè) SocketChannel, 然后將其連接到某個(gè)服務(wù)器中
當(dāng)一個(gè) ServerSocketChannel 接受到連接請(qǐng)求時(shí), 會(huì)返回一個(gè) SocketChannel 對(duì)象.
打開 SocketChannelSocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("http://example.com", 80));關(guān)閉
socketChannel.close();讀取數(shù)據(jù)
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = socketChannel.read(buf);
如果 read()返回 -1, 那么表示連接中斷了.
寫入數(shù)據(jù)String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while(buf.hasRemaining()) { channel.write(buf); }非阻塞模式
我們可以設(shè)置 SocketChannel 為異步模式, 這樣我們的 connect, read, write 都是異步的了.
socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("http://example.com", 80)); while(! socketChannel.finishConnect() ){ //wait, or do something else... }
在異步模式中, 或許連接還沒有建立, connect 方法就返回了, 因此我們需要檢查當(dāng)前是否是連接到了主機(jī), 因此通過一個(gè) while 循環(huán)來判斷.
在異步模式下, 讀寫的方式是一樣的.
在讀取時(shí), 因?yàn)槭钱惒降? 因此我們必須檢查 read 的返回值, 來判斷當(dāng)前是否讀取到了數(shù)據(jù).
ServerSocketChannel 顧名思義, 是用在服務(wù)器為端的, 可以監(jiān)聽客戶端的 TCP 連接, 例如:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); //do something with socketChannel... }打開 關(guān)閉
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.close();監(jiān)聽連接
我們可以使用ServerSocketChannel.accept()方法來監(jiān)聽客戶端的 TCP 連接請(qǐng)求, accept()方法會(huì)阻塞, 直到有連接到來, 當(dāng)有連接時(shí), 這個(gè)方法會(huì)返回一個(gè) SocketChannel 對(duì)象:
while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); //do something with socketChannel... }非阻塞模式
在非阻塞模式下, accept()是非阻塞的, 因此如果此時(shí)沒有連接到來, 那么 accept()方法會(huì)返回null:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ //do something with socketChannel... } }DatagramChannel
DatagramChannel 是用來處理 UDP 連接的.
打開DatagramChannel channel = DatagramChannel.open(); channel.socket().bind(new InetSocketAddress(9999));讀取數(shù)據(jù)
ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); channel.receive(buf);發(fā)送數(shù)據(jù)
String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); int bytesSent = channel.send(buf, new InetSocketAddress("example.com", 80));連接到指定地址
因?yàn)?UDP 是非連接的, 因此這個(gè)的 connect 并不是向 TCP 一樣真正意義上的連接, 而是它會(huì)講 DatagramChannel 鎖住, 因此我們僅僅可以從指定的地址中讀取或?qū)懭霐?shù)據(jù).
channel.connect(new InetSocketAddress("example.com", 80));
本文由 yongshun 發(fā)表于個(gè)人博客, 采用署名-非商業(yè)性使用-相同方式共享 3.0 中國大陸許可協(xié)議.
非商業(yè)轉(zhuǎn)載請(qǐng)注明作者及出處. 商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者本人
Email: [email protected]
本文標(biāo)題為: Java NIO 的前生今世 之二 NIO Channel 小結(jié)
本文鏈接為: segmentfault.com/a/1190000006824107
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65102.html
摘要:目錄源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端源碼分析之一揭開神秘的紅蓋頭服務(wù)器 目錄 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 簡介 Java NIO 的前生今世 ...
摘要:背景在工作中雖然我經(jīng)常使用到庫但是很多時(shí)候?qū)Φ囊恍└拍钸€是處于知其然不知其所以然的狀態(tài)因此就萌生了學(xué)習(xí)源碼的想法剛開始看源碼的時(shí)候自然是比較痛苦的主要原因有兩個(gè)第一網(wǎng)上沒有找到讓我滿意的詳盡的源碼分析的教程第二我也是第一次系統(tǒng)地學(xué)習(xí)這么大代 背景 在工作中, 雖然我經(jīng)常使用到 Netty 庫, 但是很多時(shí)候?qū)?Netty 的一些概念還是處于知其然, 不知其所以然的狀態(tài), 因此就萌生了學(xué)...
摘要:目錄源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端源碼分析之一揭開神秘的紅蓋頭服務(wù)器 目錄 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 簡介 Java NIO 的前生今世 ...
摘要:目錄源碼之下無秘密做最好的源碼分析教程源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端 目錄 源碼之下無秘密 ── 做最好的 Netty 源碼分析教程 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NI...
摘要:簡介是由引進(jìn)的異步由以下幾個(gè)核心部分組成和的對(duì)比和的區(qū)別主要體現(xiàn)在三個(gè)方面基于流而基于操作是阻塞的而操作是非阻塞的沒有概念而有概念基于與基于傳統(tǒng)的是面向字節(jié)流或字符流的而在中我們拋棄了傳統(tǒng)的流而是引入了和的概念在中我只能從中讀取數(shù)據(jù)到中或?qū)? 簡介 Java NIO 是由 Java 1.4 引進(jìn)的異步 IO.Java NIO 由以下幾個(gè)核心部分組成: Channel Buffer Se...
閱讀 2072·2021-11-12 10:36
閱讀 1949·2021-11-09 09:49
閱讀 2644·2021-11-04 16:12
閱讀 1189·2021-10-09 09:57
閱讀 3276·2019-08-29 17:24
閱讀 1945·2019-08-29 15:12
閱讀 1308·2019-08-29 14:07
閱讀 1318·2019-08-29 12:53