netty 4&5之学习之路_1

                                                                              **netty的线程模型**。 

           

                        

                        netty绑定端口后,开始监听连接。

             当一个连接进来后,先是由boss线程来处理accept的操作(也就是nioeventloop调度boss

线程处理,后面会细讲),当accept成功后则可以互相通讯了。如果有数据进来则将连接交给work

线程来执行读的操作,netty将数据处理为Bytebuf形式交给(其实是交给channelpipeline并且由它

来调用channelhandler)socketchannnel中的channelhandler(在连接成功后会触发channelhandler

的channelActive方法,在这里可以做一些初始的工作),这就是为什么说boss线程池处理连接,

work线程池处理io读写,也被说为io读写线程池。

             当把数据交给 work线程,通常会对进来的数据解码,这就会用到解码器,在笔者的一篇

文章中详细讲解了解码器的基础,有读者不怎么了解的可以去看看。数据编码后,netty会将数据传

给下一个handler.一般我们自己写的handler会放在最后一个,里面有我们业务操作的代码,一般项

目中在这里也是将数据投入业务处理池的位置。最后业务处理好后会想要把数据发送给客户端,所

以又会经过outhandler对数据进行解码给底层socket发送,这个操作又会交给work线程完成,work

线程会调用channel进行写操作即发送数据给

客户端。(也就是channel底层socket发送数据)

            当客户端断开连接后又会触发channelhandler的channelInActive方法。学习过Java nio的读

者应该知道reactor模式,netty也是这个模式。Java nio 中有一个selector,即多路复用器。在netty

中nioeventloopGroup充当selector的角色,nioeventloop是调度类,他负责着netty大大小小事情,

netty是事件驱动的异步框架,所以在事件驱动中也有它的影子。nioeventloopGroup包含一个或多

个nioeventloop。(本篇博客是对netty大体框架进行一个分析,细节之后博客会有详解,比如这个

调度的细节)。

一个连接对应这一个channel,一个channel对应一个nioeventloop,但是一个nioeventloop对应一

个或者多个channel。Java nio是单线程调度,而netty是多线程维护有着更好的并发处理性能。

                                                                

public class Server {

    public void stratServer(int port) throws InterruptedException {

        EventLoopGroup boss = new NioEventLoopGroup();//里面维护这boss线程池;
        EventLoopGroup work = new NioEventLoopGroup();//里面维护这work线程池


        try {
            ServerBootstrap sp = new ServerBootstrap();//netty启动辅助类

            sp.group(boss, work);
sp.channel(NioServerSocketChannel.class);//涉及到netty启动时用那个来初始化channel,在不同模式下用的类不同,一般都是NioServerSocketChannel
            sp.option(ChannelOption.SO_BACKLOG, 1024); // 连接数
            sp.option(ChannelOption.TCP_NODELAY, true); // 不延迟,消息立即发送//
            sp.childOption(ChannelOption.SO_KEEPALIVE, true); // 长连接
            sp.childHandler(new ChannelInitializer<SocketChannel>() {// 在初始化channel的时候会用到这个,调用initchannel方法装载handler,并且剔除自身即ChannelInitializer(本身也是个handler)

                        @Override
                        protected void initChannel(SocketChannel ch)
                                throws Exception {
                            ByteBuf tr=Unpooled.copiedBuffer("@".getBytes());
                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048,tr));//netty自带的解码器
                            ch.pipeline().addLast(new Handler());//用户自定义的解码器
                        }
                    });
            sp.bind(port).sync().channel().closeFuture().sync();//绑定端口,这个看起来吓人其实就是绑定端口的操作sync就是堵塞的意思,当操作完成后才不堵塞。,比如第一个sync方法指一直阻塞到bind操
完成。第二个指一直阻塞到channel关闭后才不阻塞。
        } catch (Exception e) {

        } finally {
            //完美的释放内存
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Server().stratServer(11232);
    }
}



下面这个就是笔者自定义的handler,业务入口就在channelRead0方法中。


public class Handler  extends SimpleChannelInboundHandler<Object>{


    /**
     * JFree_Wolf
     */
        @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {//接受数据,处理数据
        ByteBuf by=(ByteBuf)msg;
        System.out.println(ctx.channel().remoteAddress().toString());
        System.out.println("by大小为 "+by.readableBytes());
        //ReferenceCountUtil.release("12");
        //ctx.executor();
    //  ctx.channel().config().setWriteBufferLowWaterMark(12);
        ctx.channel().writeAndFlush("123\n").addListener(new ChannelFutureListener(){
            public void operationComplete(ChannelFuture future) throws Exception {
                System.out.println("IO操作完成");
            }
        });
    //  ctx.fireChannelRead(msg);
    }
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         System.out.println("================success connect");
         super.channelActive(ctx);
     }
       @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("server niosokcetchannel close ");
            System.out.println(t);
            super.channelInactive(ctx);
        }
       @Override
       public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
           cause.printStackTrace();
           //handler发生错误则会调用次方法。
           ctx.close();
       }
}
           这是笔者学习netty时写的demo,用来研究 DelimiterBasedFrameDecoder解码器的

用法的。 在这里推荐新手不要直接复制,这样对你的理解没有帮助,哪怕你照着代码看注释敲

一遍都对你理解比较好。学习Java,敲代码是必须的,哪怕照着敲一遍!另外这篇博客是笔者

对于netty大体框架的一个总结。但是很有很多没有解释,比如channelhadler,socketchannnel

的细节处理,他的父类,接口的用处,eventloop调用的细节,tcp/ip连接的细节 等等,这些在

之后有时间笔者会好好写一下,和大家做个交流。

                   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值