Netty - I/O模型之NIO
生活随笔
收集整理的這篇文章主要介紹了
Netty - I/O模型之NIO
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- Non Blocking I/O 同步非阻塞模型
- Code
- Server
- Client
- 日志及需要優(yōu)化的地方
- 優(yōu)化 (多路復用器)
- 小結
Non Blocking I/O 同步非阻塞模型
同步非阻塞
一個線程可以處理多個請求(連接),客戶端發(fā)送的連接請求都會注冊到多路復用器selector上,多路復用器輪詢到連接有IO請求就進行處理。
JDK1.4開始引入
Code
Server
package com.artisan.iomodel.nio;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/1/17 0:06* @mark: show me the code , change the world*/public class NioServer {// 保存客戶端連接static List<SocketChannel> channelList = new ArrayList<>();public static void main(String[] args) throws IOException {// 創(chuàng)建NIO ServerSocketChannel,與BIO的serverSocket類似ServerSocketChannel serverSocket = ServerSocketChannel.open();serverSocket.socket().bind(new InetSocketAddress(7777));// 設置ServerSocketChannel為非阻塞serverSocket.configureBlocking(false);System.out.println("服務啟動成功");while (true) {// 非阻塞模式accept方法不會阻塞,否則會阻塞// NIO的非阻塞是由操作系統(tǒng)內(nèi)部實現(xiàn)的,底層調(diào)用了linux內(nèi)核的accept函數(shù)SocketChannel socketChannel = serverSocket.accept();if (socketChannel != null) { // 如果有客戶端進行連接System.out.println("連接成功");// 設置SocketChannel為非阻塞socketChannel.configureBlocking(false);// 保存客戶端連接在List中channelList.add(socketChannel);}// 遍歷連接進行數(shù)據(jù)讀取Iterator<SocketChannel> iterator = channelList.iterator();while (iterator.hasNext()) {SocketChannel sc = iterator.next();ByteBuffer byteBuffer = ByteBuffer.allocate(128);// 非阻塞模式read方法不會阻塞,否則會阻塞int len = sc.read(byteBuffer);// 如果有數(shù)據(jù),把數(shù)據(jù)打印出來if (len > 0) {System.out.println("接收到消息:" + new String(byteBuffer.array()));} else if (len == -1) { // 如果客戶端斷開,把socket從集合中去掉iterator.remove();System.out.println("客戶端斷開連接");}}}} }Client
我們用cmd工具來連一下 , telnet 127.0.0.1 7777
回車,輸入 ctrl + ]
發(fā)送消息
日志及需要優(yōu)化的地方
舉個例子,如果連接數(shù)太多的話,會有大量的無效遍歷,假如有1萬個連接,其中只有1000個連接有寫數(shù)據(jù),但是由于其他9000個連接并沒有斷開,我們還是要每次輪詢遍歷一萬次,其中有十分之九的遍歷都是無效的…是不是有點不妥當呢?
優(yōu)化 (多路復用器)
為了優(yōu)化這個問題 , NIO引入多路復用器
package com.artisan.iomodel.nio;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; /*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/1/17 0:50* @mark: show me the code , change the world*/ public class NioSelectorServer {public static void main(String[] args) throws IOException, InterruptedException {// 創(chuàng)建NIO ServerSocketChannelServerSocketChannel serverSocket = ServerSocketChannel.open();serverSocket.socket().bind(new InetSocketAddress(7777));// 設置ServerSocketChannel為非阻塞serverSocket.configureBlocking(false);// 打開Selector處理Channel,即創(chuàng)建epollSelector selector = Selector.open();// 把ServerSocketChannel注冊到selector上,并且selector對客戶端accept連接操作感興趣serverSocket.register(selector, SelectionKey.OP_ACCEPT);System.out.println("服務啟動成功");while (true) {// 阻塞等待需要處理的事件發(fā)生selector.select();// 獲取selector中注冊的全部事件的 SelectionKey 實例Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();// 遍歷SelectionKey對事件進行處理while (iterator.hasNext()) {SelectionKey key = iterator.next();// 如果是OP_ACCEPT事件,則進行連接獲取和事件注冊if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);// 這里只注冊了讀事件,如果需要給客戶端發(fā)送數(shù)據(jù)可以注冊寫事件socketChannel.register(selector, SelectionKey.OP_READ);System.out.println("客戶端連接成功");} else if (key.isReadable()) { // 如果是OP_READ事件,則進行讀取和打印SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer byteBuffer = ByteBuffer.allocate(128);int len = socketChannel.read(byteBuffer);// 如果有數(shù)據(jù),把數(shù)據(jù)打印出來if (len > 0) {System.out.println("接收到消息:" + new String(byteBuffer.array()));} else if (len == -1) { // 如果客戶端斷開連接,關閉SocketSystem.out.println("客戶端斷開連接");socketChannel.close();}}//從事件集合里刪除本次處理的key,防止下次select重復處理iterator.remove();}}} }小結
NIO方式適用于連接數(shù)目多且連接比較短(輕操作) 的架構, 比如聊天服務器, 彈幕系統(tǒng), 服務器間通訊,但編程比較復雜
總結
以上是生活随笔為你收集整理的Netty - I/O模型之NIO的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Netty - I/O模型之BIO
- 下一篇: 深入理解分布式技术 - 从区块链技术看分