zoukankan      html  css  js  c++  java
  • 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的子类。
         */
         
    }
  • 相关阅读:
    select、poll和epoll
    Linux 常用命令之文件和目录
    SmartPlant Review 帮助文档机翻做培训手册
    SmartPlant Foundation 基础教程 3.4 菜单栏
    SmartPlant Foundation 基础教程 3.3 标题栏
    SmartPlant Foundation 基础教程 3.2 界面布局
    SmartPlant Foundation 基础教程 3.1 DTC登陆界面
    SmartPlant Foundation 基础教程 1.4 SPF架构
    SmartPlant Foundation 基础教程 1.3 SPF其他功能
    SmartPlant Foundation 基础教程 1.2 SPF集成设计功能
  • 原文地址:https://www.cnblogs.com/wonder2636/p/8989436.html
Copyright © 2011-2022 走看看