一 概念
Netty 是一款异步的事件驱动
的网络应用程序框架,支持快速的开发可维护的高性能的瞄向协议的服务端和客户端
二 核心组件
Channel
Channel是Java NIO的一个基本构造。可以看作是传入或传出数据的载体。因此,它可以被打开或关闭,连接或者断开连接。以下是常用的Channel:
-- EmbeddedChannel
-- LocalServerChannel
-- NioDatagramChannel
-- NioSctpChannel
-- NioSocketChannel
Future
Netty中所有的I/O操作都是异步
的。因为一个操作可能不会立即返回,所以我们需要一种在之后的某个时间点确定其结果的
方法。
Future 和 回调 是相互补充的机制,提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作结果的占位符
;它将在未来的某个时刻
完成,并提供对其结果的访问。
Netty 提供了ChannelFuture
,用于在执行异步操作
的时候使用。每个Netty的出站I/O操作都会返回一个ChannelFuture
。ChannelFuture能够注册一个或者多个ChannelFutureListener
实例。监听器的回调方法operationComplete()
,将会在对应的操作完成时被
调用。
ChannelHandler
Netty 的主要组件是ChannelHandler
,它充当了所有处理入站和出站数据的应用程序逻辑的容器
。
Netty 使用不同的事件来通知我们状态的改变或者是操作的状态,每个事件都可以被分发给ChannelHandler类
中某个用户实现的方法。Netty提供了大量预定义
的可以开箱即用的ChannelHandler实现
,包括用于各种协议的ChannelHandler。
ChannelPipeline
提供了ChannelHandler链
的容器,并定义了用于在该链上传播入站和出站事件流的API。使得事件流经 ChannelPipeline 是 ChannelHandler 的工作,它们是在应用程序的初始化或者引导阶段被安装的。这些对象接收事件、执行他们所实现的处理逻辑,并将数据传递给链中的下一个ChannelHandler:
EventLoop
image.png对应我们在io编程中的线程
EventLoop 定义了Netty的核心抽象,用来处理
连接的生命周期中所发生的事件
,在内部,将会为每个Channel分配一个EventLoop
。
EventLoop的管理是通过EventLoopGroup来实现的。还要一点要注意的是,客户端引导类是 Bootstrap,只需要一个EventLoopGroup。服务端引导类是 ServerBootstrap,通常需要两个 EventLoopGroup,一个用来接收客户端连接,一个用来处理 I/O 事件(也可以只使用一个 EventLoopGroup,此时其将在两个场景下共用同一个 EventLoopGroup)。
总结
- 一个 EventLoopGroup 包含
一个或者多个
EventLoop; - 一个
EventLoop
在它的生命周期内只和一个 Thread
绑定; - 所有由 EventLoop 处理的 I/O 事件都将在它专有的Thread 上被处理;
- 一个
Channel
在它的生命周期内只注册于一个EventLoop
; - NIO中,
一个 EventLoop 分配给多个 Channel
(面对多个Channel,一个 EventLoop 按照事件触发,顺序执行
); OIO中,一个 EventLoop 分配给一个 Channel。
Bootstrap 和 ServerBootstrap
BootStarp 和 ServerBootstrap 被称为引导类,指对应用程序进行配置,并使他运行起来的过程。Netty处理引导的方式是使你的应用程序和网络层相隔离。
BootStrap 是客户端的引导类,Bootstrap 在调用 bind()(连接UDP)和 connect()(连接TCP)方法时,会新创建一个 Channel,仅创建一个单独的、没有父 Channel 的 Channel 来实现所有的网络交换
image.png
ServerBootstrap 是服务端的引导类
,ServerBootstarp 在调用 bind() 方法时会创建一个ServerChannel
来接受来自客户端的连接
,并且该 ServerChannel 管理了多个子 Channel
用于同客户端之间的通信
。
三 架构图
image.png实战
启动类
package com.imooc.netty.ch3;
import com.imooc.netty.ch6.AuthHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.AttributeKey;
/**
* @author
*/
public final class Server {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, true)
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
.handler(new ServerHandler())
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new AuthHandler());
//..
}
});
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
逻辑处理类
package com.imooc.netty.ch3;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.TimeUnit;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("channelActive");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) {
System.out.println("channelRegistered");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
System.out.println("handlerAdded");
}
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
new Thread(new Runnable() {
@Override
public void run() {
// 耗时的操作
String result = loadFromDB();
ctx.channel().writeAndFlush(result);
ctx.executor().schedule(new Runnable() {
@Override
public void run() {
// ...
}
}, 1, TimeUnit.SECONDS);
}
}).start();
}
private String loadFromDB() {
return "hello world!";
}
}
服务端channel创建过程
image.png
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = this.channelFactory.newChannel();
this.init(channel);
....
反射创建服务端Channel
image.png初始化服务端Channel
image.png注册selector
image.png端口绑定
image.png总结
服务端的channel
初始化完成以后,也会被channelhandler
处理
网友评论