Netty 簡單服務器 (三)

通過對Netty的基礎認識,設計模型的初步瞭解,來寫個測試,試試手感java

上篇也說到官方推薦咱們使用主從線程池模型,那就選擇這個模型進行操做spring

 

須要操做的步驟:bootstrap

  • 須要構建兩個主從線程組
  • 寫一個服務器入口啓動器
  • 設置Channel雙向通道
  • 配置線程池處理器,操做Channel
  • 監聽機制,好比監聽啓動端口,監聽服務器關閉等等

 

利用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

-----------------------------------------------------------測試

相關文章
相關標籤/搜索