netty 简单入门
引文
因为不了解netty是什么,曾经闹过两次笑话。一次有一个兄弟说工程里没用tomcat等容器,是使用netty实现的.我当时还错判了,还有一次在rpc工程里别人问netty的版本,我又以为是一种servlet服务器,-_-||
写这个文章,是为了有初步的认识和大概的了解netty。
netty是什么
简单来说,netty是客户端和服务单交互的NIO框架。具体来说,使用netty可以快速开发出一个便捷和高效的网络交互应用,可以极大简化网络编程。netty使得网络编程和NIO变得简单易用和维护。
为什么要用及场景
今天,我们使用通用的应用程序或者类库来实现互相通讯,比如,我们经常使用一个 HTTP 客户端库来从 web 服务器上获取信息,或者通过 web 服务来执行一个远程的调用。
但是这个标准的实现没有办法很好满足的需求。我们需要实现一个异步的高效的框架,所以netty就出现了。
主要应用在互联网行业、游戏行业、大数据领域
架构简单介绍
- 丰富的缓冲实现
- 可扩展性。 可以继承ByteBuf接口,自定义实现
- 透明的零拷贝。这里说的是提供了buffer组合的功能,不必像远程的NIO一样,把多个缓冲真的copy到一个缓冲里进行处理
- 容量扩展。 这里说的是如果消息可变,实现了一个类似StringBuffer的缓冲,可以自动增长
- 统一的异步 I/O API 基于channel的接口进行多种实现,默认提供了NIO/OIO的TCP/UDP实现
- 基于拦截链模式的事件模型 在实现自己的handler时候,通过覆盖handler多个方法来实现多个事件的自定义功能
- 支持多种协议
- 支持多种transport
简单的demo和说明
这里我们使用简单事件服务器来进行说明
server handler
public class TimeServerHandler extends ChannelInboundHandlerAdapter { /** * channelActivity() 方法将会在连接建立并且准备通信时调用 * @param ctx ctx * @throws Exception 异常 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 缓冲 ByteBuf time = ctx.alloc().buffer(4); time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L)); final ChannelFuture f = ctx.writeAndFlush(time); // write和writeAndFlush都会返回一个ChannelFuture对象,并不会立即执行。为了保证 // 先写再关闭,使用listener进行关闭 f.addListener(future -> { assert f == future; ctx.close(); }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
client handler
public class TimeClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf m = (ByteBuf) msg; try { // 解析消息 long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L; System.out.println(new Date(currentTimeMillis)); ctx.close(); } finally { m.release(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
TimeServer
public class TimeServer { private int port; public TimeServer(int port) { this.port = port; } public void run() throws Exception { // NioEventLoopGroup 是用来处理I/O操作的多线程循环器 // boss 用来处理接受进来的连接 // worker 用来处理已经被接受的连接 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // ServerBootstrap 是一个启动NIO的辅助启动类。 ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { // 用来处理已经被接受的连接 @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new TimeServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); // 绑定端口,开始接受进来的连接 ChannelFuture f = bootstrap.bind(port).sync(); // 等待服务器, socket关闭 // 在这个例子中,这不会发生,但你可以优雅的关闭你的服务器 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new TimeServer(port).run(); } }
TimeClient
public class TimeClient { public static void main(String[] args) throws Exception { String host = "127.0.0.1"; int port = 8080; EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // Bootstrap和Server类似,不过不是服务单的channel, 比如客户端和无连接传输模式的channel Bootstrap b = new Bootstrap(); // 如果只指定了一个group,那么这个group既是boss也是worker b.group(workerGroup); // 客户端使用的是NioSocketChannel b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new TimeClientHandler()); } }); // 启动客户端(connect替代了bind方法) ChannelFuture f = b.connect(host, port).sync(); // 等待连接关闭 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } }
从demo上来看,我们主要在handler中实现基于事件的各种handler, 使用ServerBootstrap和Bootstrap进行启动服务端和客户端,很像其他的B/S结构。到这里我们基本了解netty是什么,简单的应用方法,到此结束。