Netty之ChannelHandler初解

目录

目标

Netty版本

Netty官方API

实战

Netty服务器

入栈ChannelHandler读入数据顺序案例

出栈ChannelHandler写出数据顺序案例

ChannelHandlerContext和NioSocketChannel写入数据时有什么不同

Pipeline添加多个ChannelHandler有什么意义


目标

  1. 掌握ChannelHandler基本使用方法。
  2. 熟悉入栈ChannelHandler和出栈ChannelHandler的执行顺序。
  3. 分析ChannelHandlerContext和NioSocketChannel写入数据时有什么不同。
  4. 了解Pipeline添加多个ChannelHandler有什么意义。

Netty版本

        <dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-all</artifactId>
			<version>4.1.87.Final</version>
		</dependency>

Netty官方API

Netty API Reference (4.1.89.Final)https://netty.io/4.1/api/index.html


实战

Netty服务器

package com.ctx.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * Netty服务器
 */
@Slf4j
public class HandlerTest {
    public static void main(String[] args) {
        new ServerBootstrap().group(new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();
                        //new HandlerTest().inboundHandlerTest(channel, pipeline);
                        //new HandlerTest().outboundHandlerTest(channel, pipeline);
                        //new HandlerTest().diff(channel, pipeline);
                        new HandlerTest().packageTest(channel, pipeline);
                    }
                }).bind(8999);
    }
}

入栈ChannelHandler读入数据顺序案例

/**
     * 入栈ChannelHandler,读入数据时,调用顺序:先加入的ChannelHandler先执行。
     */
    public void inboundHandlerTest(NioSocketChannel channel, ChannelPipeline pipeline) {
        pipeline.addLast("InboundHandler", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("InboundHandler读入数据");
                ctx.fireChannelRead(msg);
            }
        });

        pipeline.addLast("InboundHandler2", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("InboundHandler2读入数据");
                ctx.fireChannelRead(msg);
            }
        });
    }

出栈ChannelHandler写出数据顺序案例

/**
     * 出栈Handler,写出数据时,调用顺序:先加入的Handler后执行。
     */
    public void outboundHandlerTest(NioSocketChannel channel, ChannelPipeline pipeline) {
        pipeline.addLast("OutboundHandler", new ChannelOutboundHandlerAdapter() {
            @Override
            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                log.info("OutboundHandler写出数据");
                ctx.write(msg, promise);
            }
        });

        pipeline.addLast("OutboundHandler2", new ChannelOutboundHandlerAdapter() {
            @Override
            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                log.info("OutboundHandler2写出数据");
                ctx.write(msg, promise);
            }
        });
    }

ChannelHandlerContext和NioSocketChannel写入数据时有什么不同

/**
     * ChannelHandlerContext和NioSocketChannel写入数据时有什么不同?
     * ChannelHandlerContext写入数据以后,调用顺序:从当前这个Handler(有写入操作的Handler)往前出栈的Handler。
     * NioSocketChannel写入数据以后,调用顺序:从Pipeline的头部往后寻找出栈的Handler。
     */
    public void diff(NioSocketChannel channel, ChannelPipeline pipeline){
        pipeline.addLast("OutboundHandler", new ChannelOutboundHandlerAdapter() {
            @Override
            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                log.info("OutboundHandler写出数据");
                ctx.write(msg, promise);
            }
        });

        pipeline.addLast("InboundHandler", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("InboundHandler读入数据");
                ctx.writeAndFlush(channel.alloc().buffer().writeBytes("Hello World!".getBytes()));
                //channel.writeAndFlush(channel.alloc().buffer().writeBytes("Hello World!".getBytes()));
                ctx.fireChannelRead(msg);
            }
        });

        pipeline.addLast("OutboundHandler2", new ChannelOutboundHandlerAdapter() {
            @Override
            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
                log.info("OutboundHandler2写出数据");
                ctx.write(msg, promise);
            }
        });
    }

Pipeline添加多个ChannelHandler有什么意义

    /**
     * Pipeline添加多个Handler有什么意义?
     * 相当于给流水线添加了多个工序,每个工序职责不同。在不同的Handler中写不同的业务,各个出栈入栈的Handler之间还可以通过:
     * ctx.write(msg, promise)或ctx.fireChannelRead(msg)传递封装的数据。
     *
     */
    public void packageTest(NioSocketChannel channel, ChannelPipeline pipeline){
        pipeline.addLast("InboundHandler", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("InboundHandler读入数据");
                ByteBuf by = (ByteBuf) msg;
                String name = by.toString(Charset.forName("UTF-8"));
                Map<String, Object> map = new HashMap<>();
                map.put("name",name);
                ctx.fireChannelRead(map);
            }
        });

        pipeline.addLast("InboundHandler2", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("InboundHandler2读入数据");
                Map map = (Map) msg;
                map.forEach((k,v)->{
                    System.out.println(k+"="+v);
                });
                ctx.fireChannelRead(msg);
            }
        });
    }

版权声明:本文为qq_39706570原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>