Netty網(wǎng)絡(luò)編程實(shí)戰(zhàn)之搭建Netty服務(wù)器
一、Netty是什么
Netty是JBOSS開源的一款NIO網(wǎng)絡(luò)編程框架,可用于快速開發(fā)網(wǎng)絡(luò)的應(yīng)用。Netty是一個異步的、基于事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用框架,用于快速開發(fā)高性能的服務(wù)端和客戶端。可以極大的簡化基于TCP、UDP等協(xié)議的網(wǎng)絡(luò)服務(wù)。并且Netty對于各種傳輸類型(阻塞或非阻塞式的socket)、通信方式(HTTP或websocket)都提供了統(tǒng)一的API接口,提供了靈活的可擴(kuò)展性,高度可自定義的線程模型(多線程、線程池等),支持使用無連接的數(shù)據(jù)報UDP進(jìn)行通信,具有高吞吐量、低延遲、資源消耗低、最低限度的內(nèi)存復(fù)制等特性。除了優(yōu)越的性能外,Netty還支持SSL/TLS和StartTLS等加密傳輸協(xié)議,保證了數(shù)據(jù)傳輸?shù)陌踩浴?/p>
在實(shí)際使用時,Netty可以作為Socket編程的中間件;也可以和Protobuf技術(shù)結(jié)合使用,實(shí)現(xiàn)一個RPC框架,實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用;也可以作為一個websocket的長鏈接服務(wù)器,實(shí)現(xiàn)客戶端和服務(wù)端的長連接通信。
二、Hello Netty
使用Netty作為一個Web服務(wù)器,用于接收用戶請求并給出響應(yīng)。
Netty程序一般都是按套路來寫,依次編寫主程序類、自定義初始化器、自定義處理器。
1、主程序類MyNettyServerTest
通過ServerBootstrap注冊serverGroup和clientGroup兩個事件循環(huán)組,其中serverGroup用于獲取客戶端連接,clientGroup用于處理客戶端連接,類似于常見的Master-Slave結(jié)構(gòu)。
2、初始化器MyNettyServerInitializer
繼承Netty提供的初始化器ChannelInitializer。
Netty封裝了各種各樣的內(nèi)置處理器,用于實(shí)現(xiàn)各種功能。并且ChannelInitializer的initChannel()方法會在某一個連接注冊到Channel后立即被觸發(fā)調(diào)用。因此,可以根據(jù)業(yè)務(wù)需求,在initChannel()中添加若干個Netty內(nèi)置處理器,利用Netty強(qiáng)大的類庫直接處理大部分業(yè)務(wù)。最后再在initChannel()中添加一個自定義處理器,用于實(shí)現(xiàn)特定業(yè)務(wù)的具體功能。
3、自定義處理器MyNettyServerHandler
繼承SimpleChannelInboundHandler,該父類的channelRead0()方法可以接收客戶端的所有請求,并作出響應(yīng),輸出“Hello Netty”。
簡單講,Netty程序就是通過主程序類關(guān)聯(lián)自定義初始化器,然后在初始化器中加入Netty內(nèi)置處理器和自定義處理器,最后在自定義處理器中編寫處理特定需求的業(yè)務(wù)代碼。
三、代碼實(shí)例
1、maven中加入netty-all
<!-- https://mvnrepository.com/artifact/io.netty/netty-all --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.68.Final</version> </dependency>
2、主程序類MyNettyServerTest
package com.guor.demo.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * 主程序類 */ public class MyNettyServerTest { public static void main(String[] args) throws InterruptedException { /** * EventLoopGroup:事件循環(huán)組,是一個線程池,也是一個死循環(huán),用于不斷地接收用戶請求; * serverGroup:用戶監(jiān)聽及建立連接,并把每一個連接抽象為一個channel,最后再將連接交給clientGroup處理; * clientGroup:真正的處理連接 */ EventLoopGroup serverGroup = new NioEventLoopGroup(); EventLoopGroup clientGroup = new NioEventLoopGroup(); try { // 服務(wù)端啟動時的初始化操作 ServerBootstrap serverBootstrap = new ServerBootstrap(); // 1、將serverGroup和clientGroup注冊到服務(wù)端的Channel上; // 2、注冊一個服務(wù)端的初始化器MyNettyServerInitializer; // 3、該初始化器中的initChannel()方法會在連接被注冊到Channel后立刻執(zhí)行; // 5、最后將端口號綁定到8080; ChannelFuture channelFuture = serverBootstrap.group(serverGroup, clientGroup) .channel(NioServerSocketChannel.class) .childHandler(new MyNettyServerInitializer()).bind(8080).sync(); channelFuture.channel().closeFuture().sync(); }catch (Exception e){ System.out.println(e); }finally { serverGroup.shutdownGracefully(); clientGroup.shutdownGracefully(); } } }
3、初始化器MyNettyServerInitializer
package com.guor.demo.netty; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpServerCodec; /** * 初始化器 */ public class MyNettyServerInitializer extends ChannelInitializer<SocketChannel> { // 連接被注冊到Channel后,立刻執(zhí)行此方法 @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); // 加入netty提供的處理器 pipeline.addLast("HttpServerCodec",new HttpServerCodec()); // 增加自定義處理器MyNettyServerHandler,用于實(shí)際處理請求,并給出響應(yīng) pipeline.addLast("MyNettyServerHandler",new MyNettyServerHandler()); } }
4、自定義處理器MyNettyServerHandler
package com.guor.demo.netty; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; /** * 自定義處理器 * Inbound代表"進(jìn)入"的請求 */ public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception { // 定義響應(yīng)的內(nèi)容 ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8); DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf); defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain"); byteBuf.readableBytes(); // 等響應(yīng)返回給客戶端 channelHandlerContext.writeAndFlush(defaultFullHttpResponse); } }
5、通過curl http://localhost:8080訪問Netty服務(wù)
此時,可能會提示curl不是內(nèi)部或外部命令,如何解決?
四、curl不是內(nèi)部或外部命令
1、下載curl for 64-bit
2、將zip解壓到文件夾
3、在環(huán)境變量中配置
五、重寫SimpleChannelInboundHandler中一些重要的回調(diào)方法
1、重寫回調(diào)方法
package com.guor.demo.netty; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; /** * 自定義處理器 * Inbound代表"進(jìn)入"的請求 */ public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception { // 定義響應(yīng)的內(nèi)容 ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8); DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf); defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain"); byteBuf.readableBytes(); // 等響應(yīng)返回給客戶端 channelHandlerContext.writeAndFlush(defaultFullHttpResponse); } /** * 增加新處理器時,觸發(fā)此方法 */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception{ System.out.println("1、handlerAdded、增加了新的處理器"); super.handlerAdded(ctx); } /** * 當(dāng)通道被注冊到一個事件循環(huán)組EventLoop上時,觸發(fā)此方法 */ @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception{ System.out.println("2、channelRegistered、通道被注冊"); super.channelRegistered(ctx); } /** * 當(dāng)遠(yuǎn)端處于活躍狀態(tài)時(連接到了某個遠(yuǎn)端,可以收發(fā)數(shù)據(jù)),執(zhí)行此方法 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception{ System.out.println("3、channelActive、通道連接到了遠(yuǎn)端,處于活躍狀態(tài)"); super.channelActive(ctx); } /** * 當(dāng)通道處于非活躍狀態(tài)時(與遠(yuǎn)端斷開了連接),執(zhí)行此方法 */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception{ System.out.println("4、channelInactive、通道遠(yuǎn)端斷開了連接,處于非活躍狀態(tài)"); super.channelInactive(ctx); } /** * 當(dāng)通道被取消了注冊時,執(zhí)行此方法 */ @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{ System.out.println("5、channelUnregistered、通道被取消了注冊"); super.channelUnregistered(ctx); } /** * 當(dāng)程序發(fā)生異常,執(zhí)行此方法 */ @Override public void exceptionCaught(ChannelHandlerContext ctx,Throwable e) throws Exception{ System.out.println("6、exceptionCaught、程序發(fā)生了異常"); e.printStackTrace(); ctx.close(); } }
2、通過curl http://localhost:8080訪問Netty服務(wù)
3、控制臺輸出
4、ctrl + c停止訪問
以上就是Netty網(wǎng)絡(luò)編程實(shí)戰(zhàn)之搭建Netty服務(wù)器的詳細(xì)內(nèi)容,更多關(guān)于搭建Netty服務(wù)器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決創(chuàng)建springboot后啟動報錯:Failed?to?bind?properties?under‘spri
在Spring?Boot項(xiàng)目中,application.properties和application.yml是用于配置參數(shù)的兩種文件格式,properties格式簡潔但不支持層次結(jié)構(gòu),而yml格式支持層次性,可讀性更好,在yml文件中,要注意細(xì)節(jié),比如冒號后面需要空格2024-10-10用Java設(shè)計模式中的觀察者模式開發(fā)微信公眾號的例子
這篇文章主要介紹了用Java設(shè)計模式中的觀察者模式開發(fā)微信公眾號的例子,這里Java的微信SDK等部分便不再詳述,只注重關(guān)鍵部分和開發(fā)過程中觀察者模式優(yōu)點(diǎn)的體現(xiàn),需要的朋友可以參考下2016-02-02java基于jdbc實(shí)現(xiàn)簡單學(xué)生管理系統(tǒng)
本文主要主要介紹了java連接mysql數(shù)據(jù)庫的一個簡單學(xué)生系統(tǒng),通過jdbc連接數(shù)據(jù)庫。文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10Idea如何使用Fast Request接口調(diào)試
這篇文章主要介紹了Idea如何使用Fast Request接口調(diào)試問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11Java8 LocalDateTime極簡時間日期操作小結(jié)
這篇文章主要介紹了Java8-LocalDateTime極簡時間日期操作整理,通過實(shí)例代碼給大家介紹了java8 LocalDateTime 格式化問題,需要的朋友可以參考下2020-04-04Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別)
這篇文章主要介紹了Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別) ,需要的朋友可以參考下2017-02-02Java 中的 BufferedWriter 介紹_動力節(jié)點(diǎn)Java學(xué)院整理
BufferedWriter 是緩沖字符輸出流。它繼承于Writer。接下來通過本文給大家分享Java 中的 BufferedWriter知識,需要的朋友參考下吧2017-05-05java實(shí)現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法
這篇文章主要介紹了java實(shí)現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法,涉及java調(diào)用新浪微博Oauth接口的使用技巧,具有一定參考接借鑒價值,需要的朋友可以參考下2015-07-07