Netty 4 ChannelHandler和ChannelPipeline

Netty 4 ChannelHandler和ChannelPipeline

相关的接口:
1.ChannelHandler
   对应的ChannelInboundHandler和ChannelOutboundHandler
   对应的ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter
2.ChannelPipeline
3.ChannelHandlerContext


ChannelHandler
ChannelHandler是开发人员应用的主要实现组件,他充当了所有入站数据和出站数据的处理。并且ChannelHandler的方法是由网络触发的。     一般会将应用程序的业务逻辑存放在一个或者多个ChannelInboundHandler中。
实际应用中:在ChannelHandler中可实现几乎所有类型的任务,比如数据格式的转换,或者处理转换过程中所抛出的异常。

ChannelInboundHandler负责处理入站数据,ChannelOutboundHandler负责出站数据。
当某个ChannelInboundHandler的实现重写channelRead方法的时候,需要我们显式的释放与池化ByteBuf实例相关的内存。
如果是实现自SimpleChannelInboundHandler<Object>不需要显式的释放资源。因为SimpleChannelInboundHandler会自动释放资源。

public void channelRead(ChannelHandlerContext ctx,Object msg){
     ReferenceCountUtil.release(msg);
}

注意:在实现ChannelHandler中channelRead的方法中,可以执行任何业务,但是要求不要阻塞当前的IO线程,也就是说不要在channelRead方法中执行长耗时的任务。
1.当前的IO线程是啥? workGroup中定义的EventLoop分配的线程
2.为什么会导致IO线程阻塞? 因为在Channel的声明周期中所有的任务都会由注册的EventLoop去完成。如果请求的业务处理消耗大量时间,会导致EventLoop被这个任务独占,而其他注册到这个EventLoop中的Channel的读写任务会被阻塞。
3.如何解决? 如果必须阻塞调用或者执行长时间任务,可以使用一个专门的EventExecutor。

ChannelPipeline
ChannelPipeline为ChannelHandler提供了容器,多个ChannelHandler还在ChannelPipeline中按照定义的顺序传播。当一个Channel被创建的时候,他会被自动分配专属的ChannelPipeline。

当存在一个入站事件,他会从ChannelPipeline中的头部开始运动,从第一个ChannelInboundHandler开始处理,在这个过程中可能会修改数据,或者将数据格式转换为下一个ChannelInboundHandler希望得到的数据,这个取决于ChannelHandler的功能。最终会将数据传递到ChannelPipeline的尾端。

出站时间和入站类似,不过是从ChannelPipeline的尾端开始,先前传递数据直到头部,之后就是将数据传输到网络成(Socket)。



ChannelHandlerContext
当ChannelHandler在被分配到ChannelPipeline的时候,他将会分配到一个ChannelHandlerContext,通过这个对象可以将ChannelHandler和CHannelPipeline相互关联。通过通过ctx获取Pipeline、获取ChannelHandler、获取底层的Channel。最主要的是ctx可以用于写入数据。

Netty中有两种发送消息的方式,一个是直接写入Channel中,第二个是写入和ChannelHandler相关的ChannelHandlerContext中。
前者:消息从ChannelPipeline 的尾端开始流动,
后者:消息从ChannelPipeline的下一个ChannelHandler流动

public void start(int port) throws Exception {
     EventLoopGroup bossGroup = new NioEventLoopGroup(1);
     EventLoopGroup workerGroup = new NioEventLoopGroup(nettyThread);
     try {
           ServerBootstrap b = new ServerBootstrap();
           b.group(bossGroup, workerGroup)
           .channel(NioServerSocketChannel.class) // (3)
        .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        // server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码
                        ch.pipeline().addLast(new HttpResponseEncoder());
                        // server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码
                        ch.pipeline().addLast(new HttpRequestDecoder());

                        ch.pipeline().addLast(new HttpObjectAggregator(nettyLength));
                        ch.pipeline().addLast(new HttpServerInboundHandler());
                    }
                }).option(ChannelOption.SO_BACKLOG, 128) // (5)
        .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

           ChannelFuture f = b.bind(port).sync();
           f.channel().closeFuture().sync();
     } finally {
           workerGroup.shutdownGracefully();
           bossGroup.shutdownGracefully();
     }
}


liukeng
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章