【正文】netty源碼死磕1.3: html
Java NIO Channel 編程
和老的OIO相比,通道和NIO流(非阻塞IO)主要有如下幾點區別:緩存
(1)OIO流通常來講是單向的(只能讀或者寫),通道能夠讀也能夠寫。服務器
(2)OIO流值讀寫阻塞的,而通道能夠異步讀寫。網絡
(3)通道老是基於緩衝區Buffer來讀寫。dom
下面列出Java NIO中最重要的集中Channel的實現:異步
(1)FileChannelsocket
(2)DatagramChannel性能
(3)SocketChannel學習
(4)ServerSocketChannel
四種通道的說明以下:
FileChannel用於文件的數據讀寫。
DatagramChannel用於UDP的數據讀寫。
SocketChannel用於TCP的數據讀寫。
ServerSocketChannel容許咱們監聽TCP連接請求,每一個請求會建立會一個SocketChannel。
這個四種通道,涵蓋了 UDP 和 TCP網絡 IO以及文件 IO的操做。下面從通道的新建、讀取、寫入、關閉等四個操做,四種通道進行簡單的介紹。
FileChannel 是操做文件的Channel,咱們能夠經過 FileChannel 從一個文件中讀取數據,也能夠將數據寫入到文件中。
注意,FileChannel 不能設置爲非阻塞模式。
操做一:打開 FileChannel通道
RandomAccessFile aFile = new RandomAccessFile("test.txt","rw"); FileChannel inChannel = aFile.getChannel();
操做二:讀取數據
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf);
操做三:寫入數據
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); }
操做四:關閉
channel.close();
當咱們對 FileChannel 的操做完成後,必須將其關閉。
操做五:強制刷新磁盤
channel.force(true);
FileChannel的force()方法將全部未寫入的數據從通道刷新到磁盤中。在你調用該force()方法以前,出於性能緣由,操做系統可能會將數據緩存在內存中,所以您不能保證寫入通道的數據實際上寫入磁盤。
有兩種Socket通道,一個是客戶端的SocketChannel,一個是負責服務器端的Socket通道ServerSocketChannel。SocketChannel與OIO中的Socket類對應,ServerSocketChannel對應於OIO中的ServerSocket類相NIO。
兩種Socket通道新增的通道都支持阻塞和非阻塞兩種模式。在阻塞模式下的通道的建立、關閉、讀寫操做以下:
操做一:建立
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1",80));
這個是客戶端的建立。當一個服務器端的ServerSocketChannel 接受到鏈接請求時,也會返回一個 SocketChannel 對象。
操做二:讀取
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);
若是 read()返回 -1,那麼表示鏈接中斷了.
操做三:寫入數據
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); }
操做四:關閉
socketChannel.close();
在非阻塞模式,咱們能夠設置 SocketChannel 爲異步模式,這樣咱們的 connect,read,write 都是異步的了.
操做一:鏈接
socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("127.0.0.1",80)); while(! socketChannel.finishConnect() ){ //wait,or do something else... }
在異步模式中,或許鏈接尚未創建,socketChannel.connect 方法就返回了,所以咱們不斷的自旋,檢查當前是不是鏈接到了主機。
操做二:非阻塞讀寫
在異步模式下,讀寫的方式是同樣的.
在讀取時,由於是異步的,所以咱們必須檢查 read 的返回值,來判斷當前是否讀取到了數據.
ServerSocketChannel 顧名思義,是用在服務器爲端的,能夠監聽客戶端的 TCP 鏈接,例如:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); //do something with socketChannel... }
操做四:關閉
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.close();
咱們可使用ServerSocketChannel.accept()方法來監聽客戶端的 TCP 鏈接請求,accept()方法會阻塞,直到有鏈接到來,當有鏈接時,這個方法會返回一個 SocketChannel 對象:
while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); //do something with socketChannel... }
在非阻塞模式下,accept()是非阻塞的,所以若是此時沒有鏈接到來,那麼 accept()方法會返回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 是用來處理 UDP 鏈接的.
操做一:打開
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
操做二:讀取數據
ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); channel.receive(buf);
操做三:發送數據
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));
鏈接到指定地址
由於 UDP 是非鏈接的,所以這個的 connect 並非向 TCP 同樣真正意義上的鏈接,所以咱們僅僅能夠從指定的地址中讀取或寫入數據.
channel.connect(new InetSocketAddress("example.com",80));
代碼工程: JavaNioDemo.zip
下載地址:在瘋狂創客圈QQ羣文件共享。
瘋狂創客圈 Netty 死磕系列 10多篇深度文章: 【博客園 總入口】 QQ羣:104131248