JDK 程式設計
感受了上面的 java 中的 BIO/NIO/AIO 詳解,不知道你是否覺得 jdk 直接程式設計非常麻煩?
還有很多情況需要去考慮處理,還有效能相關的問題、穩定性問題,拓展性問題。
不選擇Java原生NIO程式設計的原因現在我們總結一下為什麼不建議開發者直接使用JDK的NIO類庫進行開發,具體原因如下。
(1) NIO的類庫和API繁雜,使用麻煩,你需要熟練掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
(2) 需要具備其他的額外技能做鋪墊,例如熟悉Java多執行緒程式設計。
這是因為NIO程式設計涉及到Reactor模式,你必須對多執行緒和網路程式設計非常熟悉,才能編寫出高質量的NIO程式。
(3) 可靠效能力補齊,工作量和難度都非常大。
例如客戶端面臨斷連重連、網路閃斷、半包讀寫、失敗快取、網路擁塞和異常碼流的處理等問題,NIO程式設計的特點是功能開發相對容易,但是可靠效能力補齊的工作量和難度都非常大。
(4) JDK NIO的BUG, 例如臭名昭著的epollbug,它會導致Selector空輪詢, 最終導致CPU 100%。
官方聲稱在JDK1.6版本的update18修復了該問題, 但是直到JDK1.7版本該問題仍舊存在, 只不過該BUG發生機率降低了一些而已,它並沒有得到根本性解決。
為什麼選擇 nettyNetty是業界最流行的NIO框架之一, 它的健壯性、功能、效能、可定製性和可擴充套件性在同類框架中都是首屈一指的, 它已經得到成百上千的商用專案驗證, 例如Hadoop的RPC框架Avro就使用了Netty作為底層通訊框架, 其他還有業界主流的RPC框架, 也使用Netty來構建高效能的非同步通訊能力。
透過對Netty的分析,我們將它的優點總結如下。
API使用簡單, 開發門檻低;功能強大,預置了多種編解碼功能,支援多種主流協議;定製能力強, 可以透過ChannelHandler對通訊框架進行靈活地擴充套件;效能高, 透過與其他業界主流的NIO框架對比,Netty的綜合性能最優;成熟、穩定,Netty修復了已經發現的所有JDKNIOBUG, 業務開發人員不需要再為NIO的BUG而煩惱;社群活躍, 版本迭代週期短, 發現的BUG可以被及時修復,同時, 更多的新功能會加入;經歷了大規模的商業應用考驗, 質量得到驗證。Netty在網際網路、大資料、網路遊戲、企業應用、電信軟體等眾多行業已經得到了成功商用,證明它已經完全能夠滿足不同行業的商業應用了。正是因為這些優點,Netty 逐漸成為了 Java NIO 程式設計的首選框架。
NettyNetty 是一個NIO客戶端伺服器框架,可以快速輕鬆地開發協議伺服器和客戶端等網路應用程式。
它極大地簡化並簡化了TCP和UDP套接字伺服器等網路程式設計。
“快速簡便”並不意味著最終的應用程式會受到可維護性或效能問題的影響。
Netty經過精心設計,具有豐富的協議,如FTP,SMTP,HTTP以及各種二進位制和基於文字的傳統協議。
因此,Netty成功地找到了一種在不妥協的情況下實現易於開發,效能,穩定性和靈活性的方法。
components.png
快速入門本章透過簡單的示例瀏覽Netty的核心結構,以便您快速入門。
當您在本章末尾時,您將能夠立即在Netty上編寫客戶端和伺服器。
入門之前本章中執行示例的最低要求僅為兩個:最新版本的Netty和JDK 1.6或更高版本。
maven 引入<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.17.Final</version></dependency>
例項程式碼編寫丟棄伺服器世界上最簡單的協議不是'Hello,World!',而是丟棄。
它是一種在沒有任何響應的情況下丟棄任何接收資料的協議。
要實現DISCARD協議,您唯一需要做的就是忽略所有收到的資料。
讓我們直接從處理程式實現開始,它處理由Netty生成的I/O事件。
package com.github.houbb.netty.learn.four.discard;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;public class DiscardServer { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workGroup) //在這裡,我們指定使用NioServerSocketChannel類,該類用於例項化新Channel以接受傳入連線。 .channel(NioServerSocketChannel.class) //此處指定的處理程式將始終由新接受的Channel評估。 .childHandler(new DiscardServerHandler()) // 設定套接字選項資訊 .option(ChannelOption.SO_BACKLOG, 128)// option()用於接受傳入連線的NioServerSocketChannel。// childOption()用於父ServerChannel接受的Channels,在這種情況下是NioServerSocketChannel。 .childOption(ChannelOption.SO_KEEPALIVE, true); //bind ChannelFuture channelFuture = serverBootstrap.bind(8888).syncUninterruptibly(); // Wait until the server socket is closed. // In this example, this does not happen, but you can do that to gracefully // shut down your server. channelFuture.channel().closeFuture().syncUninterruptibly(); } finally { workGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }}
EventLoopGroup 可以理解為執行緒池。
列印資訊我們如果啟動程式,最簡單的方式是使用 telnet localhost 8888 進行驗證。
public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 寫入並且重新整理 ctx.writeAndFlush(msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}
測試驗證將 server 的 handler 換成這個類。
啟動服務端。
啟動客戶端
客戶端日誌Client receive time: 1568812068058Process finished with exit code 0
感受
Netty 真的是非常的強大,api 也封裝的非常優雅,很值得深入學習。
我是老馬,期待與你的下次相遇。