Netty是一款用于创建高性能网络应用程序的高级框架。通俗地讲,其实就是远程通信框架,即rpc框架。正因为netty强大的性能,它也因此被用于很多流行框架或组件的底层通信机制。比如常见的Spring Cloud Gateway,Dubbo。它们的底层通信机制就是Netty。
由于JDK中用于操作nio的api太偏底层,使用这些底层api较为复杂。而Netty用较简单的抽象隐藏了底层实现的复杂性,封装了更为简单易用的api。
通道,作为NIO的三大组件之一。可参考 BIO/伪异步IO/NIO/AIO四种IO模型的演变 一文。
一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以在适当的时候调用前者。 Netty在内部使用回调来处理事件。
Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
(笔者感觉这段描述十分到位,因为是异步,所以我们无法同步等待获取结果,而在操作线程池的时候,执行ExecutorService.submit()接口的返回值就是Future,之前笔者一直以为这个返回值还是阻塞等待获取到的。现在看到这段描述,如醍醐灌顶。)
JDK的JUC下的Future,只允许手动检查对应的操作是否完成,或一直阻塞直到它完成,十分繁琐。因此Netty提供了自己的实现——ChannelFuture,用于在执行异步操作的时候使用。
Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。
io.netty netty-all 5.0.0.Alpha2
所有的 Netty 服务器都需要以下两部分。
// 标示一个ChannelHandler可以被多个Channel安全地共享
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelHandlerAdapter {@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// 打印异常栈跟踪cause.printStackTrace();// 关闭该Channelctx.close();}@Overridepublic 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);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {// 将未决消息冲刷到远程节点,并且关闭该Channelctx.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.创建EventLoopGroupEventLoopGroup group = new NioEventLoopGroup();try {// 2.创建ServerBootstrapServerBootstrap b = new ServerBootstrap();b.group(group).channel(NioServerSocketChannel.class) // 3.指定所使用的NIO传输Channel.localAddress(new InetSocketAddress(port)) // 4.使用指定的端口设置套接字地址.childHandler(new ChannelInitializer() { //5.添加一个EchoServerHandler到子Channel的ChannelPipelineprotected 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();}}
}
同服务端的编写类似,客户端也要通过 ChannelHandler 来实现其逻辑。只不过客户端一般会使用某个ChannelHandler的具体实现类。
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler {@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {super.channelRead(ctx, msg);}protected void messageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {}
}
上一篇:【画布---H5的新增技术】
下一篇:Linux安装IPFS