通過對Netty的基礎認識,設計模型的初步瞭解,來寫個測試,試試手感java
上篇也說到官方推薦咱們使用主從線程池模型,那就選擇這個模型進行操做spring
須要操做的步驟:bootstrap
利用IDEA快速一鍵構建一個springboot項目,而後去maven倉庫找netty依賴,找個4.x.x最新的依賴就能夠,5.x.x的版本已經被廢棄,不要使用springboot
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency>
簡單的目錄展現服務器
爲了簡單直接測試,在啓動類同級建一個NettyServer啓動類,一個main方法就能夠了,貼圖:socket
package com.yus.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; /** * Netty 啓動類 * 簡單實現客戶端發送鏈接請求,服務器返回信息 */ public class NettyServer { public static void main(String[] args) throws InterruptedException { // 1。定義兩個主從線程組 // 主線程組 --- 用於接收客戶端的鏈接,不處理事件,就是接任務的包工頭 EventLoopGroup primaryGroup = new NioEventLoopGroup(); // 從線程組 --- 處理主線程組接收鏈接註冊以後的事件,就是純打工的 EventLoopGroup subGroup = new NioEventLoopGroup(); try { // 2。服務啓動器 ServerBootstrap bootstrap = new ServerBootstrap(); // 根據Netty選擇不一樣的線程模型,選擇不一樣的重載方法,這裏是主從線程模型 // 業務的分配等功能,都由bootstrap負責處理,不須要咱們處理 // .channel --- 設置通道類型 // .childHandler 針對[subGroup從線程組]處理每個channel,能夠選擇實現類,也能夠自定義內部類的方式構建 // 每個Channel由多個handle共同組成管道(pipeline) bootstrap.group(primaryGroup, subGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInit()); // 3。綁定啓動端口,確保連接啓動,使用sync同步等待端口啓動完成 ChannelFuture future = bootstrap.bind(8088).sync(); // 4。用於監聽關閉的Channel ,同步方式 future.channel().closeFuture().sync(); } finally { //使用shutdownGracefully關閉 ,原shutdown方法已通過時 primaryGroup.shutdownGracefully(); subGroup.shutdownGracefully(); } } }
初始化器maven
package com.yus.netty; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpServerCodec; /** * 初始化器 --- 初始化每個Channel * .channel設置的類型是泛型 */ public class ChannelInit extends ChannelInitializer<SocketChannel> { /** * channel pipeline handle 三者的關係 * * 1。註冊的channel通道 * 2。進入初始化器pipeline管道 * 3。pipeline包含多個handle,共同處理channel,也能夠理解爲攔截處理 */ @Override protected void initChannel(SocketChannel channel) throws Exception { //經過 channel 獲取管道 ChannelPipeline pipeline = channel.pipeline(); //經過管道 添加handle ,name選填 //使用netty提供的一個編解碼HttpServerCodec //HttpServerCodec:當請求到服務端,須要解碼,而後響應客戶端,須要編碼 pipeline.addLast("HttpServerCodec",new HttpServerCodec()); //添加自定義的助手類 pipeline.addLast("HelloHandle",new HelloHandle()); } }
助手類ide
package com.yus.netty; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; /** * 自定義的助手類 * <p> * 客戶端向服務端發起請求以後,數據存放在緩衝區 * 而後服務端從緩衝區中讀取,總體操做是一個入棧 * <p> * SimpleChannelInboundHandler 入棧 * 要往客戶端寫點東西返回,使用HttpObject */ public class HelloHandle extends SimpleChannelInboundHandler<HttpObject> { @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { Channel channel = ctx.channel(); System.out.println("遠程地址:" + channel.remoteAddress()); //操做 緩衝區 參數(返回自定義字符串,字符集) 此處設置的字符集僅供ByteBuf使用 ByteBuf buf = Unpooled.copiedBuffer("Hello,Netty,會亂碼嗎?!", CharsetUtil.UTF_8); //構建響應,將buf數據返回 參數(http版本號,http返回狀態,) FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); //設置響應頭部的數據類型以及長度,返回須要設置charset=UTF-8,針對response設置 response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain;charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH,buf.readableBytes()); //把response響應到客戶端 //write只將response寫到緩衝區,writeAndFlush將response寫到緩衝區,並刷到客戶端 ctx.writeAndFlush(response); } }
啓動訪問: localhost:8088 oop
-----------------------------------------------------------測試