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