|
What is Netty? Netty是一个用于快速开发可维护的高性能协议服务器和客户端的异步的事件驱动网络应用框架。 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Main Components Bootstrap and ServerBootstrap EventLoop Channel ChannelFuture ChannelPipeline ChannelHandlers ChannelHandlerContext Bootstrapping a server Bootstrapping a client Bootstrapping clients from a Channel Bootstrap, EventLoop and Channel EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(workerGroup).channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new SimpleServerHandler()); } }).option(ChannelOption.SO_KEEPALIVE, true); // Bind and start to accept incoming connections. ChannelFuture f = b.bind(port).sync(); // Wait until the server socket is closed. f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } * Channel BIO 是面向流的 IO 系统(InputStream / OutputStream),系统一次一个字节(Byte)地处理数据;NIO 是面向块的 IO 系统(Channel),系统通过缓冲区(ByteBuf)批量地处理数据。 在基于Java的网络编程中,基本的构造单元就是Socket类。Netty的Channel接口提供了一个API,极大地降低了直接使用Socket的复杂性。(Channel = Connection = Socket) Channel是Netty最核心的传输API,用于所有的I/O操作。 Channel的实现是线程安全的,所以你可以保存一个Channel的引用(reference),并且在你需要写数据到远端的时候使用,即使许多线程同时在用(这个Channel)。 * EventLoop 一个EventLoopGroup包含一个或者多个EventLoop;一个Channel在它的生命周期内只注册到一个EventLoop上。 在目前Netty的模型中,EventLoop被Channel共享。这让很多Channel被最少数量的线程服务,而不是每个Channel分配一个线程。 一但Channel被指派了一个EventLoop,在它的整个生命周期过程中,都会用这个EventLoop(及其关联的线程)。 EventLoop始终由一个线程驱动,task(Runnable或者Callable)可以直接提交到EventLoop实现即刻或者延后执行。 EventLoop始终由一个线程驱动,task(Runnable或者Callable)可以直接提交到EventLoop实现即刻或者延后执行。Event和Task按FIFO(先进先出)的顺序执行。 每个EventLoop都有它自己task队列,独立于其他任何一个EventLoop。图7.3是EventLoop用来调度task的执行逻辑。这是Netty线程模型的一个关键部分。 * Bootstrap Netty的bootstrap类为一个应用的网络层配置提供了容器,包括绑定一个进程到给定的端口,或者将一个进程连接到跑在另一个特定主机和端口上的进程。 Bootstrap一个客户端只需要一个EventLoopGroup,但是一个ServerBootstrap需要2个(可以是同一个实例)。 一个服务器需要两组不同的Channel。第一组包含一个绑定到一个本地端口,代表了服务器自身监听socket的ServerChannel。第二组包括所有用来处理收到连接的Channel—每个被服务器接受的连接。 ServerChannel关联的EventLoopGroup(boss)分配一个EventLoop来负责创建处理连接请求的Channel。一旦一个连接被接受,第二个EventLoopGroup(worker)会分配一个EventLoop给这个连接的Channel。 The Channel Lifecycle 一个Channel正常的生命周期如图6.1所示。随着状态发生变化,相应的event产生。这些event被转发到ChannelPipeline中的ChannelHandler来采取相应的操作。 ChannelFuture Netty中所有的I/O操作都是异步的。因为一个操作可能不会立刻返回,我们需要一个方法在稍后的时间来判定它的结果。因此,Netty提供了ChannelFuture,它的addListener()方法注册一个ChannelFutureListener,当操作完成时可以收到通知(无论成功与否)。 Example: ChannelFuture f = ctx.writeAndFlush(time); f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { assert f == future; ctx.close(); } }); ChannelPipeline 一个ChannelPipeline可以看成是一串ChannelHandler实例,拦截穿过Channel的输入输出event。 每个新创建的Channel都会分配一个新的ChannelPipeline。当一个Channel(Connection)被创建,它会自动被分配一个ChannelPipeline。这个关系是恒定的,Channel不可以换别ChannelPipeline,也不可以解除掉当前分配的ChannelPipeline。在Netty组件的整个生命周期中这个关系是固定的,不需要开发者采取什么操作。 Example: ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(sslCtx.newHandler(ch.alloc())); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new SimpleServerHandler()); // A custom handler ChannelHandlers ChannelHandler是Netty的主要组件,它作为一个应用逻辑的容器,处理输入输出数据。 让event在管道中运转是ChannelHandler们的工作:这些ChannelHandler对象接收event,执行已经实现了的处理逻辑,然后传递数据到链中的下一个handler。 Example: public class SimpleServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // do something } @Override public void channelActive(final ChannelHandlerContext ctx) { // do something } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // do something } } ChannelHandlerContext 当一个ChannelHandler被加入一个ChannelPipeline时,就被分配了一个ChannelHandlerContext。ChannelHandlerContext代表了一个ChannelHandler和ChannelPipeline直接的绑定关系。 一个event可以被一个ChannelInboundHandler或者ChannelOutboundHandler处理。接下来,通过调用ChannelHandlerContext的方法,它会被转发到下一个同类型的handler。 虽然说ChannelHandlerContext这个对象可以被用来获取底层的Channel,但是它主要是被用来写输出数据的。 Netty中有两种发送消息的方法。你可以直接写到Channel中,或者写到一个ChannelHandler相关的ChannelHandlerContext中。前者让消息从ChannelPipeline的尾部开始发送,而后者让消息从ChannelPipeline中的下一个handler开始发送。 你可以通过调用ChannelHandlerContext的pipeline方法来获取绑定的ChannelPipeline引用。 其他的高级应用还包括把一个ChannelHandlerContext的引用放入缓存,待后来使用。稍后在使用该引用时,可能不在ChannelHandler方法内,甚至可能在另一个线程里。 因为一个ChannelHandler可以属于多个ChannelPipeline,所以它可以绑定多个ChannelHandlerContext实例。想要实现这个用法的ChannelHandler必须加上注解@Sharable;否则,试图将它添加到多个ChannelPipeline时会触发一个异常。显然,想要在多并发channel(也就是连接)中保证线程安全,这样的一个ChannelHandler必须是线程安全的类 总结: Client和Server建立一个Connection(Socket),Netty对应创建一个Channel,一个Channel对应一个ChannelPeiline,ChannelPipeline里有多个ChannelHandler实例组成,每个ChannelHandler对应一个ChannelHandlerContext。 ServerBootstrap会创建两个EventLoopGroup:Boss和Worker,EventLoopGrouup包含多个EventLoop,每个EventLoop对应一个线程,一个EventLoop关联多个Channel。 一个EventLoop相当于一个EventExecutor,一个Event相当于一个Task(Runnable或者Callable),一个Event提交到EventLoop,EventLoop单线程执行该Event。 Reference: http://www.slideshare.net/bluegrayhe/netty-indroduction 转载请并标注: “本文转载自 linkedkeeper.com ” ©著作权归作者所有 |
