目錄
Java NIO和Netty NIO比較
Java NIO:
Netty:
Netty NIO中的主要模塊
Transport(傳輸層)
Buffer(緩沖區(qū))
Codec(編解碼器)
Handler(處理器)
EventLoop(事件循環(huán))
Bootstrap和Channel(引導(dǎo)和通道)
Future和Promise(異步編程)
Netty示例
服務(wù)端時(shí)序圖
服務(wù)端代碼
客戶端時(shí)序圖
客戶端代碼
總結(jié)
Java NIO和Netty NIO比較
Java NIO:
-
原生Java庫: Java NIO是Java標(biāo)準(zhǔn)庫的一部分,提供了非阻塞I/O的核心功能。它是Java平臺(tái)上的底層API,允許開發(fā)者直接操作通道、緩沖區(qū)和選擇器等組件。
-
較低級(jí)別: Java NIO是相對(duì)較低級(jí)別的API,需要開發(fā)者編寫更多的底層代碼來處理網(wǎng)絡(luò)通信和協(xié)議。這可以提供更多的控制權(quán),但也增加了開發(fā)復(fù)雜性。
-
多路復(fù)用: Java NIO通過選擇器(Selector)實(shí)現(xiàn)多路復(fù)用,允許一個(gè)線程管理多個(gè)通道。這對(duì)于處理大量并發(fā)連接非常有用。
-
手動(dòng)管理緩沖區(qū): Java NIO需要開發(fā)者手動(dòng)管理緩沖區(qū),包括分配、讀取、寫入和釋放緩沖區(qū)。這可能導(dǎo)致更復(fù)雜的代碼結(jié)構(gòu)。
-
適用場(chǎng)景: Java NIO適用于需要高度自定義的網(wǎng)絡(luò)協(xié)議網(wǎng)絡(luò)服務(wù)器。它在性能和靈活性方面提供了更多的控制權(quán)。
Netty:
-
高級(jí)別框架: Netty是一個(gè)基于Java NIO的高級(jí)別框架,它封裝了底層的NIO細(xì)節(jié),提供了更簡(jiǎn)單和強(qiáng)大的API來處理網(wǎng)絡(luò)通信。
-
事件驅(qū)動(dòng): Netty是事件驅(qū)動(dòng)的框架,使用事件處理器(Event Handlers)來處理入站和出站事件。這使得編寫網(wǎng)絡(luò)應(yīng)用程序更加模塊化和可維護(hù)。
-
自動(dòng)管理緩沖區(qū): Netty自動(dòng)管理緩沖區(qū),無需開發(fā)者手動(dòng)分配和釋放緩沖區(qū)。這減輕了內(nèi)存管理的負(fù)擔(dān)。
-
豐富的功能: Netty提供了豐富的功能,包括HTTP、WebSocket、TLS/SSL支持、UDP通信、拆包和粘包處理等。它還支持異步和同步I/O操作。
-
社區(qū)和生態(tài)系統(tǒng): Netty擁有強(qiáng)大的社區(qū)支持和豐富的生態(tài)系統(tǒng),有大量的擴(kuò)展和插件可用。這使得開發(fā)人員可以更快地構(gòu)建復(fù)雜的網(wǎng)絡(luò)應(yīng)用。
-
適用場(chǎng)景: Netty適用于構(gòu)建高性能、可擴(kuò)展、可維護(hù)的網(wǎng)絡(luò)應(yīng)用程序,特別是在處理協(xié)議復(fù)雜、并發(fā)連接眾多的情況下。
為什么選擇Netty?
Java NIO | Netty NIO | |
---|---|---|
API和類庫 | 繁雜麻煩,需掌握Selector、Channel、Buffer等 | 封裝簡(jiǎn)單,門檻低 |
擴(kuò)展實(shí)現(xiàn) | 需要熟悉多線程和網(wǎng)絡(luò)編程保證代碼質(zhì)量 | 通過ChannelHandler對(duì)框架靈活擴(kuò)展 |
可靠性 | 可靠性能力需手動(dòng)補(bǔ)齊,工作量和難度大 | 預(yù)編碼、多協(xié)議,功能強(qiáng),性能高 |
Bug Fixed | 臭名昭著的epoll bug(selector空輪詢,CPU到100%)1.6版本說修復(fù),1.7版本還在,只是調(diào)低了觸發(fā)率 | 穩(wěn)定,成熟,修復(fù)了所有已發(fā)現(xiàn)的Java NIO Bug |
社區(qū)生態(tài) | / | 社區(qū)活躍,迭代周期短 |
生存迭代 | / | 經(jīng)歷大規(guī)模商業(yè)應(yīng)用考驗(yàn),質(zhì)量得到驗(yàn)證 |
基礎(chǔ)篇我們使用Java NIO舉例演示了簡(jiǎn)單的RPC通信。代碼的行數(shù)和步驟確實(shí)挺繁瑣,不如來看看Netty 的操作,是騾子是馬牽出來溜溜先,就當(dāng)諸君飯后消個(gè)食。
Netty NIO中的主要模塊
Netty是一個(gè)強(qiáng)大的網(wǎng)絡(luò)編程框架,它由多個(gè)主要模塊組成,每個(gè)模塊負(fù)責(zé)不同的功能。以下是Netty中的一些主要模塊:
-
Transport(傳輸層)
-
NIO: 這個(gè)模塊實(shí)現(xiàn)了基于Java NIO的傳輸層,提供了非阻塞的網(wǎng)絡(luò)通信功能。它包括
NioEventLoopGroup
、NioServerSocketChannel
、NioSocketChannel
等類,用于創(chuàng)建和管理NIO通道。
-
-
Buffer(緩沖區(qū))
-
Java NIO中的ByteBuffer局限性:
-
ByteBuffer長(zhǎng)度固定,不能動(dòng)態(tài)伸縮和擴(kuò)展,編碼對(duì)象時(shí)容易引起索引越界異常
-
ByteBuffer只有一個(gè)標(biāo)識(shí)位置的指針position,需要手工調(diào)用flip()和rewind(),不方便
-
ByteBuffer的API功能有限,需要使用者自己編程實(shí)現(xiàn)一些高級(jí)和實(shí)用的特性
-
-
為了彌補(bǔ)這些不足,Netty NIO提供了自己的實(shí)現(xiàn)——ByteBuf:
Netty提供了高性能的緩沖區(qū)實(shí)現(xiàn)ByteBuf,用于處理數(shù)據(jù)的讀取和寫入。ByteBuf提供了直接和間接緩沖區(qū),并支持池化,以減少內(nèi)存分配和回收的開銷。
-
-
Codec(編解碼器)
-
編碼器和解碼器: 這個(gè)模塊包括一系列編解碼器,用于將數(shù)據(jù)序列化和反序列化為字節(jié),以便在網(wǎng)絡(luò)中傳輸。Netty提供了JSON、Protobuf、HTTP、WebSocket等多種編解碼器。
-
-
Handler(處理器)
-
ChannelHandler:
ChannelHandler
是Netty中的核心概念,用于處理事件和數(shù)據(jù)。它可以自定義,用于構(gòu)建處理鏈。Netty提供了各種內(nèi)置的ChannelHandler
,如SimpleChannelInboundHandler
、ChannelDuplexHandler
等。
-
-
EventLoop(事件循環(huán))
-
EventLoopGroup: 這個(gè)模塊包括了
EventLoopGroup
和EventLoop
,用于實(shí)現(xiàn)事件循環(huán)機(jī)制。EventLoopGroup
管理一組EventLoop
,每個(gè)EventLoop
負(fù)責(zé)處理一組通道上的事件。事件循環(huán)是Netty實(shí)現(xiàn)異步和事件驅(qū)動(dòng)的關(guān)鍵。
-
-
Bootstrap和Channel(引導(dǎo)和通道)
-
ServerBootstrap和Bootstrap: 這兩個(gè)類用于引導(dǎo)Netty應(yīng)用程序的啟動(dòng)。
ServerBootstrap
用于啟動(dòng)服務(wù)器端,而Bootstrap
用于啟動(dòng)客戶端。 -
Channel和ChannelPipeline:
Channel
表示通道,它代表了一個(gè)網(wǎng)絡(luò)連接。在Channel接口層,采用Fade模式進(jìn)行統(tǒng)一封裝。ChannelPipeline
是處理鏈,包含一系列ChannelHandler
,用于處理事件和數(shù)據(jù)。
-
-
Future和Promise(異步編程)
-
Future: Netty使用
Future
來表示異步操作的結(jié)果,允許開發(fā)者異步地等待操作完成。 -
Promise:
Promise
是Future
的擴(kuò)展,允許開發(fā)者設(shè)置操作的結(jié)果,使得異步編程更加方便。
-
Netty示例
服務(wù)端時(shí)序圖
服務(wù)端代碼
/** * Netty Server * 開始:需要綁定端口用于啟動(dòng) * 1.創(chuàng)建線程組bossGroup用于處理客戶端連接 * 2.創(chuàng)建線程組workGroup用于socket網(wǎng)絡(luò)讀寫 * 3.創(chuàng)建Bootstrap服務(wù)啟動(dòng)輔助類,類似serverSocketChannel * 4.鏈?zhǔn)骄幊蹋瑯?gòu)造線程組、serverChannel、options、channelHandle * 5.ChannelHandle繼承自ChannelInitializer<SocketChannel>進(jìn)行功能擴(kuò)展 * 結(jié)束:優(yōu)雅退出關(guān)閉資源 */ public class Server { ? ?public static void main(String[] args) { ? ? ? ?new Server().bind(8088); ? } ? ? ?/** ? ? * 綁定端口用于啟動(dòng) ? ? * @param port 服務(wù)端口 ? ? */ ? ?public void bind(int port) { ? ? ? ?// 1.創(chuàng)建線程組bossGroup處理客戶端連接 ? ? ? ?EventLoopGroup bossGroup = new NioEventLoopGroup(); ? ? ? ?// 2.創(chuàng)建線程組workGroup用于socket網(wǎng)絡(luò)讀寫 ? ? ? ?EventLoopGroup workerGroup = new NioEventLoopGroup(); ? ? ? ?try { ? ? ? ? ? ?// 3.創(chuàng)建Bootstrap服務(wù)啟動(dòng)輔助類,類似serverSocketChannel ? ? ? ? ? ?ServerBootstrap server = new ServerBootstrap(); ? ? ? ? ? ?// 4.鏈?zhǔn)骄幊?,?gòu)造線程組、serverChannel、options、channelHandle ? ? ? ? ? ?server.group(bossGroup, workerGroup) ? ? ? ? ? ? ? ? ? .channel(NioServerSocketChannel.class) ? ? ? ? ? ? ? ? ? .option(ChannelOption.SO_BACKLOG, 1024) ? ? ? ? ? ? ? ? ? .childHandler(new ChildChannelHandler()); ? ? ? ? ? ?System.out.println("server start on port:" + port); ? ? ? ? ? ? ?// 綁定端口異步調(diào)用連接客戶端,同步阻塞等待(連接結(jié)果)連接成功 ? ? ? ? ? ?ChannelFuture channelFuture = server.bind(port).sync(); ? ? ? ? ? ? ?// 異步調(diào)用close關(guān)閉鏈路,同步阻塞等待(關(guān)閉結(jié)果)關(guān)閉成功后退出main函數(shù) ? ? ? ? ? ?channelFuture.channel().closeFuture().sync(); ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } finally { ? ? ? ? ? ?// 優(yōu)雅退出關(guān)閉資源 ? ? ? ? ? ?bossGroup.shutdownGracefully(); ? ? ? ? ? ?workerGroup.shutdownGracefully(); ? ? ? } ? } ? ? ?/** ? ? * 5.ChannelHandle繼承自ChannelInitializer<SocketChannel>進(jìn)行功能擴(kuò)展 ? ? */ ? ?private class ChildChannelHandler extends ChannelInitializer<SocketChannel> { ? ? ? ? ?@Override ? ? ? ?protected void initChannel(SocketChannel socketChannel) throws Exception { ? ? ? ? ? ?socketChannel.pipeline().addLast(new ServerHandler()); ? ? ? } ? } ? ? ?private class ServerHandler extends ChannelHandlerAdapter { ? ? ? ?@Override ? ? ? ?public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ? ? ? ? ? ?ByteBuf buf = (ByteBuf) msg; ? ? ? ? ? ?byte[] req = new byte[buf.readableBytes()]; // 讀取緩沖區(qū)可讀取長(zhǎng)度 ? ? ? ? ? ?buf.readBytes(req); ? ? ? ? ? ?String body = new String(req, "UTF-8"); ? ? ? ? ? ?System.out.println("Server receive msg:" + body); ? ? ? ? ? ?String currTime = "query time".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "error code"; ? ? ? ? ? ?ByteBuf resp = Unpooled.copiedBuffer(currTime.getBytes()); ? ? ? ? ? ?ctx.write(resp); ? ? ? } ? ? ? ? ?@Override ? ? ? ?public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ? ? ? ? ? ?ctx.close(); ? ? ? } ? ? ? ? ?@Override ? ? ? ?public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ? ? ? ? ? ?ctx.flush(); // 將發(fā)送緩沖數(shù)組中的消息通過flush()寫入socketChannel發(fā)送,避免了頻繁調(diào)用selector進(jìn)行發(fā)送 ? ? ? } ? } }
客戶端時(shí)序圖
客戶端代碼
/** * 開始:連接服務(wù)端ip:port * 1.創(chuàng)建EventLoopGroup管理socket讀取 * 2.創(chuàng)建客戶端輔助類Bootstrap,類似于之前的SocketChannel * 3.鏈?zhǔn)骄幊?,?gòu)造客戶端流程client、option、handler * 4.handler使用的是ChannelInitializer<SocketChannel> * 結(jié)束:優(yōu)雅的關(guān)閉資源 */ public class Client { ? ?public static void main(String[] args) { ? ? ? ?new Client().connect("localhost", 8088); ? } ? ? ?/** ? ? * 連接服務(wù)端ip:port ? ? * @param ip 服務(wù)端地址 ? ? * @param port 服務(wù)端端口 ? ? */ ? ?public void connect(String ip, int port) { ? ? ? ?// 1.創(chuàng)建EventLoopGroup管理socket讀取 ? ? ? ?EventLoopGroup group =new NioEventLoopGroup(); ? ? ? ?try { ? ? ? ? ? ?// 2.創(chuàng)建客戶端輔助類Bootstrap,類似于之前的SocketChannel ? ? ? ? ? ?Bootstrap client = new Bootstrap(); ? ? ? ? ? ?// 3.鏈?zhǔn)骄幊?,?gòu)造客戶端流程client、option、handler ? ? ? ? ? ?client.group(group).channel(NioSocketChannel.class) ? ? ? ? ? ? ? ? ? .option(ChannelOption.TCP_NODELAY, true) ? ? ? ? ? ? ? ? ? .handler(new ChannelInitializer<SocketChannel>() { ? ? ? ? ? ? ? ? ? ? ? ?@Override ? ? ? ? ? ? ? ? ? ? ? ?protected void initChannel(SocketChannel socketChannel) throws Exception { ? ? ? ? ? ? ? ? ? ? ? ? ? ?socketChannel.pipeline().addLast(new ClientHandler()); ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? }); ? ? ? ? ? ? ?// 發(fā)起異步連接操作 ? ? ? ? ? ?ChannelFuture channelFuture = client.connect(ip, port).sync(); ? ? ? ? ? ? ?// 等待服務(wù)端鏈路關(guān)閉 ? ? ? ? ? ?channelFuture.channel().closeFuture().sync(); ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } finally { ? ? ? ? ? ?// 優(yōu)雅退出,釋放資源 ? ? ? ? ? ?group.shutdownGracefully(); ? ? ? } ? } ? ? ?/** ? ? * 4.handler使用的是ChannelInitializer<SocketChannel> ? ? */ ? ?public class ClientHandler extends ChannelHandlerAdapter { ? ? ? ?@Override ? ? ? ?public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ? ? ? ? ? ?ByteBuf buf = (ByteBuf) msg; ? ? ? ? ? ?byte[] req = new byte[buf.readableBytes()]; ? ? ? ? ? ?buf.readBytes(req); ? ? ? ? ? ?String body = new String(req, "UTF-8"); ? ? ? ? ? ?System.out.println("client receive server send:" + body); ? ? ? ? ? ?channelActive(ctx); ? ? ? } ? ? ? ? ?@Override ? ? ? ?public void channelActive(ChannelHandlerContext ctx) throws Exception { ? ? ? ? ? ?Scanner scanner = new Scanner(System.in); ? ? ? ? ? ?System.out.println("請(qǐng)輸入"); ? ? ? ? ? ?String clientIn = scanner.nextLine(); ? ? ? ? ? ?ByteBuf firstMessage = Unpooled.buffer(clientIn.getBytes().length); ? ? ? ? ? ?firstMessage.writeBytes(clientIn.getBytes()); ? ? ? ? ? ?System.out.println("client send:" + clientIn); ? ? ? ? ? ?ctx.writeAndFlush(firstMessage); ? ? ? } ? ? ? ?@Override ? ? ? ?public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ? ? ? ? ? ?ctx.close(); ? ? ? } ? } }
運(yùn)行結(jié)果:
總結(jié)
不難看出,不管是流程步驟還是實(shí)現(xiàn)功能的代碼行數(shù),Netty NIO都是優(yōu)于Java原生NIO的。到此,一個(gè)簡(jiǎn)單的NIO入門示例完成。文章來源:http://www.zghlxwxcb.cn/news/detail-726605.html
資料參考:《Netty權(quán)威指南》文章來源地址http://www.zghlxwxcb.cn/news/detail-726605.html
到了這里,關(guān)于聊聊分布式架構(gòu)06——[NIO入門]簡(jiǎn)單的Netty NIO示例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!