Netty系列-初識Netty
從今天開始我們進入Netty系列。
一起探索下面幾個問題,將使我們對Netty有一個初步的了解。
-
為什么都不使用大家都不用Java原生的Nio,Aio,Bio來實現(xiàn)服務(wù)架構(gòu)了?而是使用Netty,那么它的優(yōu)勢是什么?
-
Netty支持的協(xié)議有哪些?
-
為什么說Netty是事件驅(qū)動的異步模型?
-
如何開啟一個Netty服務(wù)端?
Netty的優(yōu)勢是什么
Netty 是一個基于 Java 的高性能網(wǎng)絡(luò)應(yīng)用框架,它提供了一種簡單、靈活、可擴展的方式來開發(fā)網(wǎng)絡(luò)應(yīng)用程序。
雖然 Java 原生的 NIO(New I/O)和 AIO(Asynchronous I/O)等API 也可以用于網(wǎng)絡(luò)編程,但是 Netty 在以下幾個方面提供了更多的優(yōu)勢,這也是為什么人們更喜歡使用 Netty 而不是 Java 原生庫的原因:
-
簡化了網(wǎng)絡(luò)應(yīng)用程序的開發(fā):Netty 提供了高度抽象的編程模型,使得開發(fā)人員能夠更輕松地構(gòu)建復(fù)雜的網(wǎng)絡(luò)應(yīng)用程序。它的設(shè)計理念是面向?qū)ο蟮模峁┝艘唤M易于使用的組件和工具,簡化了網(wǎng)絡(luò)編程的復(fù)雜性。 -
高性能和可伸縮性:Netty 在性能方面進行了優(yōu)化,并提供了許多高級功能,如零拷貝技術(shù)和事件驅(qū)動的異步模型。這些優(yōu)化使得 Netty 在處理高并發(fā)和大規(guī)模連接時表現(xiàn)出色,并且具有較低的資源消耗。 -
更好的可維護性和擴展性:Netty 的設(shè)計模式和組件使得代碼更易于維護和擴展。它提供了一套強大的解碼器和編碼器,使得數(shù)據(jù)的處理和轉(zhuǎn)換更加靈活和可擴展。此外,Netty 還支持插件機制,可以方便地集成其他第三方庫和工具。 -
更豐富的功能:Netty 提供了豐富的功能集,如心跳檢測、SSL/TLS 支持、WebSocket 支持、流量整形和拆包/粘包處理等。這些功能在實際應(yīng)用中很常用,可以幫助開發(fā)人員更快速地構(gòu)建高性能的網(wǎng)絡(luò)應(yīng)用程序。 -
社區(qū)活躍和成熟度高:Netty 是一個開源項目,擁有龐大的社區(qū)支持。它的開發(fā)團隊經(jīng)驗豐富,有著長期的開發(fā)和維護歷史。這意味著 Netty 在穩(wěn)定性、Bug 修復(fù)和功能改進方面有著較高的可靠性。
Netty支持的協(xié)議有哪些?
-
TCP(傳輸控制協(xié)議):Netty 提供了強大的 TCP 協(xié)議支持,能夠構(gòu)建高性能的 TCP 服務(wù)器和客戶端應(yīng)用程序。 -
UDP(用戶數(shù)據(jù)報協(xié)議):Netty 支持 UDP 協(xié)議,使得開發(fā)者可以輕松地構(gòu)建基于 UDP 的應(yīng)用程序,如實時音視頻傳輸、游戲服務(wù)器等。 -
HTTP(超文本傳輸協(xié)議):Netty 提供了全面的 HTTP 協(xié)議支持,包括 HTTP 客戶端和服務(wù)器的實現(xiàn)。它支持 HTTP/1.0、HTTP/1.1 和 HTTP/2,能夠處理 Web 請求和響應(yīng),并提供了豐富的 HTTP 相關(guān)功能。 -
WebSocket:Netty 支持 WebSocket 協(xié)議,使得開發(fā)者可以構(gòu)建實時的雙向通信應(yīng)用程序,如聊天應(yīng)用、實時消息推送等。 -
SPDY:Netty 提供了 SPDY 協(xié)議的支持,SPDY 是一種優(yōu)化的網(wǎng)絡(luò)傳輸協(xié)議,用于加速 Web 頁面的加載速度。 -
HTTP/2:Netty 也支持 HTTP/2 協(xié)議,HTTP/2 是對 HTTP/1.1 的改進,提供了更高效的多路復(fù)用、頭部壓縮、服務(wù)器推送等特性,能夠提升 Web 應(yīng)用的性能。
除了以上列舉的協(xié)議,Netty 還支持更多的網(wǎng)絡(luò)協(xié)議,
如 SMTP(簡單郵件傳輸協(xié)議)、FTP(文件傳輸協(xié)議)、DNS(域名系統(tǒng)協(xié)議)等。
同時,Netty 還提供了靈活的 API 和可擴展的架構(gòu),開發(fā)者可以自定義協(xié)議滿足特定應(yīng)用需求。
為什么說Netty是事件驅(qū)動的異步模型?
Netty 是異步事件驅(qū)動的框架,該框架體現(xiàn)為所有的I/O操作都是異步的,所有的I/O調(diào)用會立即返回,并不保證調(diào)用成功與否,但是調(diào)用會返回ChannelFuture。Netty 會通過 ChannelFuture通知調(diào)用是成功了還是失敗了,亦或是取消了
當(dāng)Future對象剛剛創(chuàng)建時,處于非完成狀態(tài),調(diào)用者可以通過返回的ChannelFuture來獲取操作執(zhí)行的狀態(tài),再通過注冊監(jiān)聽函數(shù)來執(zhí)行完成后的操作
例:
future.addListener((ChannelFutureListener)?callback?->?{
???????????boolean?success?=?callback.isSuccess();
???????????if?(success)?{
??????????????//操作SUCCESS??
??????????}?else?{
???????????????//操作失敗的情況todo...
??????????}
??????});
常見有如下操作:
-
通過
isDone方法來判斷當(dāng)前操作是否完成。 -
通過
isSuccess方法來判斷已完成的當(dāng)前操作是否成功。 -
通過
getCause方法來獲取已完成的當(dāng)前操作失敗的原因。 -
通過
isCancelled方法來判斷已完成的當(dāng)前操作是否被取消。 -
通過
addListener方法來注冊監(jiān)聽器,當(dāng)操作已完成(isDone方法返回完成),將會通知指定的監(jiān)聽器;如果future對象已完成,則通知指定監(jiān)聽器。
如何開啟一個Netty服務(wù)端
要開啟一個Netty服務(wù)端 首先在Java項目中 引入maven依賴;
??????<dependency>
??????????<groupId>io.netty</groupId>
??????????<artifactId>netty-all</artifactId>
??????????<version>4.1.70.Final</version>
??????</dependency>
創(chuàng)建NioNettyServer
public?class?NioNettyServer?{
???@Value("${nio.netty.server.port:?10010}")
???private?int?port;
???@Autowired
???private?NettyServerChannelInitializer?nettyServerChannelInitializer;
???@Async
???public?void?start()?{
???????log.info("start?to?netty?server?port?is?{}",?port);
???????//?接收連接
???????EventLoopGroup?boss?=?new?NioEventLoopGroup();
???????//?處理信息
???????EventLoopGroup?worker?=?new?NioEventLoopGroup();
???????try?{
???????????//?定義server
???????????ServerBootstrap?serverBootstrap?=?new?ServerBootstrap();
???????????//?添加分組
???????????serverBootstrap.group(boss,?worker)
???????????????????//?添加通道設(shè)置非阻塞
??????????????????.channel(NioServerSocketChannel.class)
???????????????????//?服務(wù)端可連接隊列數(shù)量
??????????????????.option(ChannelOption.SO_BACKLOG,?128)
???????????????????//?開啟長連接
??????????????????.childOption(ChannelOption.SO_KEEPALIVE,?Boolean.TRUE)
???????????????????//?流程處理
??????????????????.childHandler(nettyServerChannelInitializer);
???????????//?綁定端口
???????????ChannelFuture?cf?=?serverBootstrap.bind(port).sync();
???????????//?優(yōu)雅關(guān)閉連接
???????????cf.channel().closeFuture().sync();
??????}?catch?(Exception?e)?{
???????????log.error("connection?error:{}",?e.getMessage(),?e);
??????}?finally?{
???????????boss.shutdownGracefully();
???????????worker.shutdownGracefully();
??????}
??}
}
創(chuàng)建NettyServerChannelInitializer
@Component
@Slf4j
public?class?NettyServerChannelInitializer?extends?ChannelInitializer?{
???@Autowired
???private?ClientMessageHandler?clientMessageHandler;
???@Override
???protected?void?initChannel(Channel?channel)?{
???????//?設(shè)置編碼類型
???????channel.pipeline().addLast("decoder",new?HexDecoder());
???????//?設(shè)置解碼類型
???????channel.pipeline().addLast("encoder",new?HexEncoder());
???????//?消息業(yè)務(wù)處理
???????channel.pipeline().addLast("ClientMessageHandler",clientMessageHandler);
??}
}
創(chuàng)建消息處理Handler
public?class?ClientMessageHandler?extends?SimpleChannelInboundHandler<String>?{
???/**
????*?設(shè)備接入連接時處理
????*
????*?@param?ctx
????*/
???@Override
???public?void?handlerAdded(ChannelHandlerContext?ctx)?throws?RedisConnectException?{
???????Channel?channel?=?ctx.channel();
???????log.info("netty有新的連接:[{}]",?channel.remoteAddress());
??}
???/**
????*?設(shè)備有新的數(shù)據(jù)發(fā)送過來時
????*
????*?@param?ctx
????*/
???@Override
???public?void?channelRead0(ChannelHandlerContext?ctx,?String?msg)?throws?RedisConnectException?{
log.info("netty有新的數(shù)據(jù):[{}]",?msg);
??}
???@Override
???public?void?exceptionCaught(ChannelHandlerContext?ctx,?Throwable?cause)?{
???????Channel?channel?=?ctx.channel();
???????if?(cause?instanceof?IllegalArgumentException)?{
???????????log.warn("業(yè)務(wù)異常請排查,?{}",?cause.getMessage(),?cause);
??????}
???????log.error("error?message?{},channel:{}",?cause.getMessage(),?channel.remoteAddress());
??}
???/**
????*?斷開連接
????*?@param?ctx?s下文
????*/
???@Override
???public?void?handlerRemoved(ChannelHandlerContext?ctx)?throws?Exception?{
???????Channel?channel?=?ctx.channel();
???????log.error("netty客戶端-斷開連接,ip:{}",?channel.remoteAddress());
??}
}
在啟動類中添加:
public?static?void?main(String[]?args)?{
ConfigurableApplicationContext?context?=??SpringApplication.run(App.class,?args);
context.getBean(NioNettyServer.class).start();
}
啟動后日志輸出如下信息,證明netty服務(wù)端啟動成功。
總結(jié):
Netty 的設(shè)計思想強調(diào)了可重用性、靈活性和可擴展性。它提供了豐富的 API,包括對各種網(wǎng)絡(luò)協(xié)議的支持,如 TCP、UDP、HTTP、WebSocket 等。開發(fā)人員可以通過簡單的配置和自定義處理器來構(gòu)建自己的網(wǎng)絡(luò)應(yīng)用程序,并根據(jù)具體需求進行靈活的定制。
Netty 還提供了許多高級功能,如高性能的序列化框架、心跳機制、SSL/TLS 支持、拆包與粘包處理、流量控制等,使得開發(fā)人員能夠快速地構(gòu)建安全、可靠且高效的網(wǎng)絡(luò)應(yīng)用程序。
