• netty初步认识


    package com.hhr.demo;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.codec.http.DefaultFullHttpResponse;
    import io.netty.handler.codec.http.FullHttpResponse;
    import io.netty.handler.codec.http.HttpHeaderNames;
    import io.netty.handler.codec.http.HttpRequest;
    import io.netty.handler.codec.http.HttpResponseStatus;
    import io.netty.handler.codec.http.HttpServerCodec;
    import io.netty.handler.codec.http.HttpVersion;
    import io.netty.util.CharsetUtil;
    
    //@SpringBootApplication
    public class Demo1Application {
    
        public static void main(String[] args) throws  Exception {
            
    //           SpringApplication.run(Demo1Application.class, args);
            
            /**
             * 定义好EventLoopGroup,定义好Bootstrap(ServerBootstrap)以及使用的channel类型(一般就是NioSocketChannel,
             * 服务端是NioServerSocketChannel),剩下是业务相关,使用的ChannelInitializer和具体的handler。
             * 主要就是2+N(N为自定义的handler数量)个类.
             * 为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的。Netty应用中必不可少的组件:
                Bootstrap or ServerBootstrap
                EventLoop
                EventLoopGroup
                ChannelPipeline
                Channel
                Future or ChannelFuture
                ChannelInitializer
                ChannelHandler
                 Bootstrap,一个Netty应用通常由一个Bootstrap开始,它主要作用是配置整个Netty程序,串联起各个组件。
                 Handler,为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。
                 ChannelInboundHandler,一个最常用的Handler。这个Handler的作用就是处理接收到数据时的事件,也就是说,我们的业务逻辑一般就是写在这个Handler里面的,ChannelInboundHandler就是用来处理我们的核心业务逻辑。
                 ChannelInitializer,当一个链接建立时,我们需要知道怎么来接收或者发送数据,当然,我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。
                 ChannelPipeline,一个Netty应用基于ChannelPipeline机制,这种机制需要依赖于EventLoop和EventLoopGroup,因为它们三个都和事件或者事件处理相关。
                 EventLoops的目的是为Channel处理IO操作,一个EventLoop可以为多个Channel服务。
                 EventLoopGroup会包含多个EventLoop。
                 Channel代表了一个Socket链接,或者其它和IO操作相关的组件,它和EventLoop一起用来参与IO处理。
                 Future,在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。
             */
                EventLoopGroup bossGroup = new NioEventLoopGroup(2);
                EventLoopGroup workerGroup = new NioEventLoopGroup(4);//第一个EventLoopGroup用来专门负责绑定到端口监听连接事件,而把第二个EventLoopGroup用来处理每个接收到的连接
                /**
                 *  1、 如果不指定线程数,则线程数为:CPU的核数*2
    
                    2、根据线程个数是否为2的幂次方,采用不同策略初始化chooser
                    
                    3、产生nThreads个NioEventLoop对象保存在children数组中。
                    
                    可以理解NioEventLoop就是一个线程,线程NioEventLoop中里面有如下几个属性:
                    
                    1、NioEventLoopGroup (在父类SingleThreadEventExecutor中)
                    
                    2、selector
                    
                    3、provider
                    
                    4、thread (在父类SingleThreadEventExecutor中)
                    
                    更通俗点就是: NioEventLoopGroup就是一个线程池,NioEventLoop就是一个线程。NioEventLoopGroup线程池中有N个NioEventLoop线程。
                 */
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                try {
                    /**
                     *  1、group:workerGroup保存在 ServerBootstrap对象的childGroup属性上。 bossGroup保存在ServerBootstrap对象的group属性上
    
                        2、channelFactory:BootstrapChannelFactory类的对象(clazz属性为:NioServerSocketChannel.class)
                        
                        3、handler:SimpleServerHandler
                        
                        4、childHandler
                     */
                    serverBootstrap.group(bossGroup, workerGroup)
                            /**
                             * 这行代码的作用为通过反射产生来一个NioServerSocketChannel类的实例,其中这个NioServerSocketChannel类对象有这样几个属性:
                             * SocketChannel、NioServerSocketChannelConfig 、SelectionKey.OP_ACCEPT事件、NioMessageUnsafe、DefaultChannelPipeline
                             */
                            .channel(NioServerSocketChannel.class)//当一个连接到达,Netty会注册一个channel,然后EventLoopGroup会分配一个EventLoop绑定到这个channel,在这个channel的整个生命周期过程中,都会由绑定的这个EventLoop来为它服务,而这个EventLoop就是一个线程
                            .childHandler(new MyChannelInitializer());
                    ChannelFuture future = serverBootstrap.bind(8999).sync();
                    future.channel().closeFuture().sync();
                } finally {
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();
                }
        }
    }
    
    class MyChannelInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
    //        pipeline上添加来一个ChannelInitializer对象,其中重写来initChannel方法。该方法通过p.addLast()向serverChannel的流水线处理器中加入了一个 ServerBootstrapAcceptor, 
    //        从名字上就可以看出来,这是一个接入器,专门接受新请求,把新的请求扔给某个事件循环器
            ChannelPipeline pipeline = ch.pipeline();
    //        pipeline.addLast(new HttpRequestDecoder());
    //        pipeline.addLast(new HttpResponseEncoder());
            /**
             * 由于NioEventLoopGroup中维护着多个NioEventLoop,next方法回调用chooser策略找到下一个NioEventLoop,并执行该对象的register方法进行注册。
             */
            pipeline.addLast("httpServerCodec", new HttpServerCodec());
            System.out.println("---------------------");
            pipeline.addLast(new MyHttpHandler());
        }
    }
    
    
    /**
     *  netty自带了对用的codec类比较方便。
        pipeline.addLast("httpServerCodec", new HttpServerCodec());
        自己实现的handler最简单的方式用SimpleChannelInboundHandler接收HttpRequest方法即可
        class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest>
        这里简单说下SimpleChannelInboundHandler这个类,他是简化处理接受信息并处理的一个类,主要做两件事。
        
        第一件事是根据泛型决定是否处理这个消息,能够处理就自己处理,不行就交给下一个(可以参考acceptInboundMessage和channelRead方法)。
        第二件事是消息的自动回收(有构造函数支持 默认是true),消息的引用计数会减一(所以在其他地方还要使用记得再retain一下)。
        不过只用这个handler并不能拿到content,还需要配合ChunkedWriteHandler和HttpObjectAggregator得到FullHttpRequest对象
     *
     */
    class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
            
            System.out.println("*********************************************************");
            System.out.println(msg.getClass());
            System.out.println(msg.uri());
            System.out.println(msg.method().name());
            System.out.println(ctx.channel().remoteAddress());
            System.out.println("headers:");
            msg.headers().forEach(System.out::println);
            ByteBuf buf = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
            ctx.writeAndFlush(response);
    //         ctx.channel().close();
        }
    
        /**
         *  处理WebSocket请求 #
            只需要在上面的基础上增加一个WebSocketServerProtocolHandler即可,完整如下:
        pipeline.addLast("httpServerCodec", new HttpServerCodec());
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast(new HttpObjectAggregator(8096));
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
               自己的处理器可以接收并处理WebSocketFrame的子类。
         */
         
    }
  • 相关阅读:
    mysql详解9:触发器和事件
    mysql详解7:视图
    mysql详解6:字符串函数 日期函数 IF CASE
    mysql详解5:复杂查询
    [转]Kubernetes网络组件之Calico策略实践(BGP、RR、IPIP)
    Springcloud 学习笔记05-Mybatis-Plus
    Git学习笔记04--tortoisegit的clone、pull、commit操作、分支的新增、合并、删除
    Git学习笔记03--Git客户端(TortoiseGit)安装与基本使用
    Java 项目bug记录过程--Failed to configure a DataSource
    TiDB学习笔记02-场景案例综述
  • 原文地址:https://www.cnblogs.com/wonder2636/p/8989436.html
Copyright © 2020-2023  润新知