• 1.- Netty设计理念-异步和事件驱动


    0. 关键点

    a). 非阻塞网络调用,异步方法立即返回
    b). 选择器(Selector)使得单一线程就可监控很多连接上的事件。
    
    	<dependency>
    		<groupId>io.netty</groupId>
    		<artifactId>netty-all</artifactId> <!-- Use 'netty-all' for 4.0 or above -->
    		<version>4.1.13</version>
    		<scope>compile</scope>
    	</dependency>
    

    1.1 Channel-类似socket,管道

    1.2 回调-操作完成时调用

    1.3 Future-异步通知--更精确的异步

    类似更精确的异步。
    JDK预置concurrent.Future需要手动检查对应的操作是否已完成,非常繁琐。
    Netty封装成ChannelFuture消除手动检查,可注册一或多个ChannelFutureListner,回调方法operationComplete()操作完成时调用,可检查是成功还是失败了。

    Channel channel = null;
    ChannelFuture future = channel.connect(new InetSocketAddress("127.0.0.1", 8888));
    //注册监测异步事件调用完成
    future.addListener(new ChannelFutureListener() {
    	@Override
    	public void operationComplete(ChannelFuture future) throws Exception {
    		if( future.isSuccess()){
    			//异步调用成功
    			ByteBuf buffer = Unpooled.copiedBuffer("Hello", CharsetUtil.UTF_8);
    			future.channel().write(buffer);
    		} else {
    			//异步调用失败
    			Throwable cause = future.cause();
    			cause.printStackTrace();
    		}
    	}
    });
    

    1.4 事件和ChannelHandler-链

    1.5 EventLoop-处理所有IO事件-多线程处理

    为每一个channel分配一个EventLoop,处理所有的事件,包括:注册感兴趣的事件、将事件派发给ChannelHandler,安排进一步的动作。
    EventLoop本身只由一个线程驱动,处理一个Channel的所有IO事件,并且在整个生命周期不变(不需考虑同步问题)。

    1.8 实例代码

    1.8.1 server代码

    //测试结果
    Received Connect, remote IP:/127.0.0.1:56015	//c连接上时打印
    channelRead Invoked!!
    Server Received:1111111111111111111111111
    channelReadComplete Invoked!!!
    Received Connect, remote IP:/127.0.0.1:56018
    
    public class EchoServer {
        public static void main(String[] args) throws InterruptedException {
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                ServerBootstrap b = new ServerBootstrap();  //引导类,BS端不同
                b.group(bossGroup, workerGroup)     //master主线程,slaves处理handler的线程池
                        .channel(NioServerSocketChannel.class)  //何种channel(socket),BS端不同
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            //当一个新连接被接受时,一个新的子channel被创建,将处理类实例添加到ChannelPipeLine(链)中
                            @Override
                            public void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new EchoServerHandler());
                            }
                        });
    
                //绑定端口,sync()阻塞到调用完成
                ChannelFuture f = b.bind(8888).sync();
                //阻塞到关闭完成
                f.channel().closeFuture().sync();
            } finally {
                //关闭EventLoopGroup直到完成
                bossGroup.shutdownGracefully().sync();
                workerGroup.shutdownGracefully().sync();
            }
        }
    }
    
    public class EchoServerHandler  extends ChannelInboundHandlerAdapter{
        @Override
        public void channelActive(ChannelHandlerContext ctx){
            System.out.println("Received Connect, remote IP:"+ctx.channel().remoteAddress());
        }
    
        @Override
        //对每个传入的消息都要调用,存在TCP粘连的问题
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            System.out.println("channelRead Invoked!!");
            ByteBuf in = (ByteBuf) msg;
            System.out.println("Server Received:" + in.toString(CharsetUtil.UTF_8));
            ctx.write(in);
        }
    
        @Override
        //读取完当前批次消息时调用
        public void channelReadComplete(ChannelHandlerContext ctx){
            System.out.println("channelReadComplete Invoked!!!");
            ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    
        @Override
        //捕捉发生的异常
        public void exceptionCaught( ChannelHandlerContext ctx , Throwable cause){
            cause.printStackTrace();
            ctx.close();
        }
    }
    

    1.8.2 Client代码

    //测试结果
    channelActive Invoked!!!!!
    Client received:Netty rocks
    
    public class EchoClient {
        public static void main(String[] args) throws InterruptedException {
            EventLoopGroup group = new NioEventLoopGroup();
    
            try {
                Bootstrap b = new Bootstrap();
                b.group(group)
                        .channel(NioSocketChannel.class)
                        .remoteAddress("127.0.0.1", 8888)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                socketChannel.pipeline().addLast(new EchoClientHandler());
                            }
                        });
                ChannelFuture f = b.connect().sync();
                f.channel().closeFuture().sync();
            }finally {
                group.shutdownGracefully().sync();
            }
        }
    }
    
    public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf>{
    
        @Override
        public void channelActive( ChannelHandlerContext ctx){
            System.out.println("channelActive Invoked!!!!!");
            ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks", CharsetUtil.UTF_8));
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
            System.out.println("Client received:"+byteBuf.toString(CharsetUtil.UTF_8));
        }
    
        @Override
        public  void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
            cause.printStackTrace();
            ctx.close();
        }
    }
    
  • 相关阅读:
    k8镜像
    幂等设计
    复杂思考,简单设计。 https://mp.weixin.qq.com/s/xmkFzEpzIauJgus3MMmkaQ
    GDP Streaming RPC 设计
    The zero value for a Mutex is an unlocked mutex. 零值
    reflect.DeepEqual 反射 比较值相等
    Go 和 C 的变量定义异同 nil 值判断 汇编
    https://www.luogu.com.cn/blog/wangrx/finitecalculus
    HTML a标签链接 设置点击下载文件 react 路由 静态路由 动态路由 虚拟路由
    Mars 微信跨平台跨业务基础组件
  • 原文地址:https://www.cnblogs.com/Desneo/p/7299808.html
Copyright © 2020-2023  润新知