Netty-内置的 ChannelHandler

26 篇文章 1 订阅
13 篇文章 0 订阅
  • ChannelInboundHandlerAdapter--输入数据处理器

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    ctx.fireChannelRead(msg);
}

接收上一个 handler 的输出,这里的 msg 就是上一个 handler 的输出。默认情况下 adapter 会通过 fireChannelRead() 方法直接把上一个 handler 的输出结果传递到下一个 handler。

往 pipeline 添加的第一个 handler 中的 channelRead 方法中,msg 对象其实就是 ByteBuf。服务端在接受到数据之后,应该首先要做的第一步逻辑就是把这个 ByteBuf 进行解码,然后把解码后的结果传递到下一个 handler,如:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf requestByteBuf = (ByteBuf) msg;
        // 解码
        Packet packet = PacketCodeC.INSTANCE.decode(requestByteBuf);
        // 解码后的对象传递到下一个 handler 处理
        ctx.fireChannelRead(packet)
}

 

  • ChannelOutboundHandlerAdapter--输出数据处理器

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ctx.write(msg, promise);
}

默认情况下,这个 adapter 也会把对象传递到下一个 outBound 节点,它的传播顺序与 inboundHandler 相反

  • ByteToMessageDecoder--输入数据转换处理器

public class PacketDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        String msg=in.toString(Charset.forName("utf-8"));

        //在out中增加了对象,但是却没有读in时,避免出现异常:PacketDecoder.decode() did not read anything but decoded a message
        in.skipBytes(in.readableBytes());

        //通过往这个 List 里面添加解码后的结果对象,就可以自动实现结果往下一个 handler 进行传递
        //Netty 会自动进行内存的释放
        out.add(msg);
    }
}

通过往这个 List 里面添加解码后的结果对象,就可以自动实现结果往下一个 handler 进行传递
​​​​并且Netty 会自动进行ByteBuf内存的释放 

public class MyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        System.out.println("收到消息:"+msg.toString());

    }
}

 

public class NettyServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup=new NioEventLoopGroup();
        EventLoopGroup workerGroup=new NioEventLoopGroup();

        ServerBootstrap bootstrap=new ServerBootstrap()
                .group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new PacketDecoderHanderl());
                        ch.pipeline().addLast(new MyServerHandler());
                    }
                });
        ChannelFuture channelFuture = bootstrap.bind(9999);
        channelFuture.addListener(future -> {
            if(future.isSuccess()){
                System.out.println("成功");
            }else {
                System.out.println("失败");
            }
        });
    }
}

 

  • MessageToByteEncoder--输出数据转换处理器

1 登录成功后直接向通道中写入java对象 

public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginRequestEntity> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginRequestEntity msg) throws Exception {
        //登录逻辑
        System.out.println("登录信息="+msg);

        //直接写入java对象:LoginResponseEntity
        ctx.channel().writeAndFlush(new LoginResponseEntity(msg.getUsername(),msg.getPassword()));
    }
}

 2 Netty会根据写入的java对象的类型和MessageToByteEncoder处理器的泛型进行匹配,在处理器中把java对象转为二进制写入到缓存就可以了。MessageToByteEncoder处理器只会关心泛型类的输出,所以如果输出的java对象没有相对应的输出处理器,者不会有任何输出。

public class LoginResponseHandler extends MessageToByteEncoder<LoginResponseEntity> {
    @Override
    protected void encode(ChannelHandlerContext ctx, LoginResponseEntity msg, ByteBuf out) throws Exception {
        String m="欢迎登录:"+msg.getUsername();
        //把java对象转为二进制写入到缓存
        out.writeBytes(m.getBytes());
    }
}

3 配置处理器

//解析传来的数据为实体
ch.pipeline().addLast(new PacketDecoderHanderl());
//登录处理器
ch.pipeline().addLast(new LoginRequestHandler());
//登录响应处理器
ch.pipeline().addLast(new LoginResponseHandler());
  • SimpleChannelInboundHandler--去掉if else语句

public class LoginRequestHandler extends SimpleChannelInboundHandler<LoginEntity> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginEntity msg) throws Exception {
        //登录逻辑
        System.out.println("登录信息="+msg);

        ByteBuf buffer = ctx.alloc().ioBuffer();
        buffer.writeBytes("登录成功".getBytes());

        ctx.writeAndFlush(buffer);
    }
}

ByteToMessageDecoder解码后会把解码后的信息类型传给处理器,通过SimpleChannelInboundHandler的范型类,就可以达到自动选择hander处理器,实现省略if elsse语句的目的。(注意,ByteToMessageDecoder处理器一定要配置在SimpleChannelInboundHandler的前面)

//解析传来的数据为实体
ch.pipeline().addLast(new PacketDecoderHanderl());
//登录处理器
 ch.pipeline().addLast(new LoginRequestHandler());
//处理String的处理器
ch.pipeline().addLast(new MyServerHandler());
... ...

一次请求和响应的处理器调用示例图

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值