Netty笔记(二)ChannelHandler和ChannelPipline

Netty所有的数据传输处理都需要在ChannelPipline中的ChannelHandler来处理,这次我们来看看Netty是怎么处理这些数据的。

首先我们需要分清楚什么是出站数据,什么是入站数据。

出站数据:是指你需要发送的数据,不论你是客户端还是服务器只要是写进Channel里的数据都是出站的数据。

入站数据:是指你接收到的数据,不论你是客户端还是服务器,对方写进Channel里的数据,对于你来说都是入站数据。

现在我们来说说看ChannelPipline怎么处理出站数据和入站数据的。

入站数据都是从头部开始处理,pipline会先调用第一个ChannelInboundHandler,第一个消费后调用fireChannelRead方法触发下一个Handler的channelRead方法,如果不调用fireChannelRead方法,那么数据传递就到此为止。

对于出站数据如果通过调用Channel的write方法写数据的,数据会从Channelpipline的尾端开始传递,会先调用第一个ChannelOutboundHandler,只有Handler调用ChannelHandlerContext的write,才会继续触发下一个Handler,如果调用Channel的write数据将重头开始传递。

我们来定义一个服务端,并打印出日志看一下数据的流转过程

ServerIn1 的代码如下


@Slf4j
public class ServerInChannelAdapter1 extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        log.debug("服务器收到消息:{}",in.toString(CharsetUtil.UTF_8));
        ctx.fireChannelRead(msg);

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.debug("服务器读取完成");
        ctx.fireChannelReadComplete();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("服务器异常",cause);
        //关闭连接
        ctx.close();
    }
}

ServerIn2的代码

@Slf4j
public class ServerInChannelAdapter2 extends ChannelInboundHandlerAdapter {
    

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        log.debug("服务器收到消息:{}",in.toString(CharsetUtil.UTF_8));
        //读取完成后需要手动释放
        ReferenceCountUtil.release(in);

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.debug("服务器读取完成");
        //从尾部  发送数据
        ctx.channel().writeAndFlush(Unpooled.copiedBuffer("这里是服务器收到请回复",CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("服务器异常",cause);
        //关闭连接
        ctx.close();
    }
}

ServerOut1  和ServerOut2 代码一样的,代码如下

@Slf4j
public class ServerOutChannelAdapter1 extends ChannelOutboundHandlerAdapter {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        log.debug("服务器写入数据-> {}", ((ByteBuf) msg).toString(CharsetUtil.UTF_8));
        ctx.write(msg);
        promise.setSuccess();
    }

    @Override
    public void flush(ChannelHandlerContext ctx) throws Exception {
        log.debug("服务器刷新数据");
        ctx.flush();
    }
}

服务器端的Handler添加顺序如下

  public void start() throws InterruptedException {
        //线程组
        group = new NioEventLoopGroup();
        //服务器
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(group)
                //设置非阻塞的服务器Socket连接
                .channel(NioServerSocketChannel.class)
                //绑定端口
                .localAddress(new InetSocketAddress(port))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline()
                                .addLast(new ServerInChannelAdapter1())
                                .addLast(new ServerOutChannelAdapter1())
                                .addLast(new ServerInChannelAdapter2())
                                .addLast(new ServerOutChannelAdapter2());
                    }
                });
        //绑定端口,并获取Channel
        channelFuture = bootstrap.bind().sync();
    }

执行的结果如下

11:25:43.816 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerInChannelAdapter1 - 服务器收到消息:这里是客户端,收到请回复
11:25:43.817 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerInChannelAdapter2 - 服务器收到消息:这里是客户端,收到请回复
11:25:43.818 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerInChannelAdapter1 - 服务器读取完成
11:25:43.818 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerInChannelAdapter2 - 服务器读取完成
11:25:43.825 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerOutChannelAdapter2 - 服务器写入数据-> 这里是服务器收到请回复
11:25:43.825 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerOutChannelAdapter1 - 服务器写入数据-> 这里是服务器收到请回复
11:25:43.826 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerOutChannelAdapter2 - 服务器刷新数据
11:25:43.826 [nioEventLoopGroup-2-2] DEBUG com.github.xuejike.javap2p.server.channel.ServerOutChannelAdapter1 - 服务器刷新数据

 

### 关于 Netty 的学习笔记与教程 #### 什么是 NettyNetty 是一个异步事件驱动的网络应用程序框架,旨在快速开发可维护的高性能协议服务器客户端[^1]。它广泛应用于 Java 领域中的高并发场景,例如分布式系统、微服务通信以及实时消息传递。 --- #### 黑马程序员 Netty 学习资源推荐 以下是针对 Netty 学习的一些优质资料汇总: 1. **官方文档** 官方文档是最权威的学习材料之一,涵盖了从门到高级的各种主题。可以通过阅读官方指南了解 Netty 的核心概念及其 API 使用方式。 2. **GitHub Gitee 上的 Demo 案例仓库** 提供了一个名为 `netty-learn` 的项目库,分别托管在 GitHub Gitee 平台上。这些仓库包含了丰富的实践案例,帮助开发者更好地理解掌握 Netty 的实际应用场景。 - GitHub 地址:[https://github.com/](https://github.com/) - Gitee 地址:[https://gitee.com/](https://gitee.com/) 3. **黑马程序员相关课程** 黑马程序员提供了全面的 Java 架构师培训体系,其中包括 Dubbo、Redis、ZooKeeper、Spring Cloud 等技术栈的内容,同时也覆盖了 Netty 的基础知识实战技巧[^2]。具体可以关注其官网或者联系客服获取最新课程安排。 4. **核心技术解析** - 创建 NioEventLoopGroup 实现线程池加 Selector 功能[^3]。 - Bootstrap 初始化流程详解,包括线程池配置、通道类型设定、Socket 参数调整以及 ChannelHandler 注册等内容[^4]。 - 单例模式下的 @ChannelHandler.Sharable 注解作用说明。 --- #### 示例代码片段 以下是一个简单的 Netty 客户端启动过程演示: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); // (1) try { Bootstrap bootstrap = new Bootstrap(); // (2) bootstrap.group(group) // (3) .channel(NioSocketChannel.class) // (4) .handler(new ClientInitializer()); // (6) ChannelFuture future = bootstrap.connect("localhost", 8080).sync(); // (7) future.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } } ``` 上述代码展示了如何利用 Netty 开发基本的客户端程序,涉及到了多个重要环节的操作步骤。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值