Netty(二)——Netty简介、核心组件及如何编写

一、简介

Netty是一款用于创建高性能网络应用程序的高级框架。通俗地讲,其实就是远程通信框架,即rpc框架。正因为netty强大的性能,它也因此被用于很多流行框架或组件的底层通信机制。比如常见的Spring Cloud Gateway,Dubbo。它们的底层通信机制就是Netty。

由于JDK中用于操作nio的api太偏底层,使用这些底层api较为复杂。而Netty用较简单的抽象隐藏了底层实现的复杂性,封装了更为简单易用的api。

二、核心组件

1、Channel

        通道,作为NIO的三大组件之一。可参考 BIO/伪异步IO/NIO/AIO四种IO模型的演变 一文。

2、回调

        一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以在适当的时候调用前者。 Netty在内部使用回调来处理事件。

3、Future

        Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。

(笔者感觉这段描述十分到位,因为是异步,所以我们无法同步等待获取结果,而在操作线程池的时候,执行ExecutorService.submit()接口的返回值就是Future,之前笔者一直以为这个返回值还是阻塞等待获取到的。现在看到这段描述,如醍醐灌顶。)

        JDK的JUC下的Future,只允许手动检查对应的操作是否完成,或一直阻塞直到它完成,十分繁琐。因此Netty提供了自己的实现——ChannelFuture,用于在执行异步操作的时候使用。

4、事件和ChannelHandler

        Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。

三、编写Netty服务端和客户端

1、引入Netty的maven依赖

    
    
        io.netty
        netty-all
        5.0.0.Alpha2
    

2、Netty服务端编写

所有的 Netty 服务器都需要以下两部分。

  • 至少一个 ChannelHandler——该组件实现了服务器对从客户端接收的数据的处理,即它的业务逻辑。
  • 引导——这是配置服务器的启动代码。至少,它会将服务器绑定到它要监听连接请求的端口上。

// 标示一个ChannelHandler可以被多个Channel安全地共享
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelHandlerAdapter {

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 打印异常栈跟踪
        cause.printStackTrace();
        // 关闭该Channel
        ctx.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
        // 将接收到的消息写给发送者,而不冲刷出战消息
        ctx.write(in);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // 将未决消息冲刷到远程节点,并且关闭该Channel
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }
}
public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        if (args.length != -1) {
            System.err.println("Usage: " + EchoServer.class.getSimpleName() + " ");
        }
        // 设置端口值(如果端口参数的格式不正确,则抛出一个NumberFormatException)
        int port = Integer.parseInt(args[0]);
        new EchoServer(port).start();
    }

    public void start() throws Exception {
        final EchoServerHandler serverHandler = new EchoServerHandler();
        // 1.创建EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            // 2.创建ServerBootstrap
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class) // 3.指定所使用的NIO传输Channel
                    .localAddress(new InetSocketAddress(port)) // 4.使用指定的端口设置套接字地址
                    .childHandler(new ChannelInitializer() {  //5.添加一个EchoServerHandler到子Channel的ChannelPipeline
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // EchoServerHandler被标注为@Shareable,所以我们可以总是使用同样的实例
                            ch.pipeline().addLast(serverHandler);
                        }
                    });
            ChannelFuture f = b.bind().sync(); // 6.异步地绑定服务器;调用sync()方法阻塞等待直到绑定完成
            f.channel().closeFuture().sync(); // 7.获取Channel的CloseFuture,并且阻塞当前线程直到它完成
        } finally {
            // 8.关闭EventLoopGroup,释放所有的资源
            group.shutdownGracefully().sync();
        }
    }
}

3、Netty客户端编写

 同服务端的编写类似,客户端也要通过 ChannelHandler 来实现其逻辑。只不过客户端一般会使用某个ChannelHandler的具体实现类。

@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler {

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        super.channelRead(ctx, msg);
    }

    protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {

    }
}

你可能感兴趣的:(Netty,netty,rpc,远程通信)