Netty 是由 JBOSS 提供一个异步的、 基于事件驱动的网络编程框架。
一,Netty线程模型
Netty 抽象出两组线程池, BossGroup 专门负责接收客户端连接, WorkerGroup 专门负责网络读写操作。 NioEventLoop 表示一个不断循环执行处理任务的线程, 每个 NioEventLoop 都有一个 selector, 用于监听绑定在其 上的 socket 网络通道。 NioEventLoop 内部采用串行化设计, 从消息的读取->解码->处理->编码->发送, 始终由 IO 线 程 NioEventLoop 负责。
二,核心组件
ChannelHandler
ChannelHandler 接口定义了许多事件处理的方法, 可以通过重写这些方法去实现具体的业务逻辑 我们经常需要自定义一个 Handler 类去继承 ChannelInboundHandlerAdapter, 然后通过重写相应方法实现业务逻辑
public void channelActive(ChannelHandlerContext ctx), 通道就绪事件
public void channelRead(ChannelHandlerContext ctx, Object msg), 通道读取数据事件
public void channelReadComplete(ChannelHandlerContext ctx) , 数据读取完毕事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause), 通道发生异常事件
ChannelPipeline
ChannelPipeline 是一个 Handler 的集合, 它负责处理和拦截 inbound 或者 outbound 的事件和操作, 相当于一个 贯穿 Netty 的链,一个ChannelPipeline中可以有多个handler,但是对于已经存在的ChannelPipeline只会提供addFirst,addLast前插与后插两种方式。
ChannelHandlerContext
事件处理器上下文对象 , Pipeline链中的实际处理节点 。 每个处理节点ChannelHandlerContext 中包含一个具体的事件处理器 ChannelHandler , 同时ChannelHandlerContext 中也绑定了对应的 pipeline 和 Channel 的信息,方便对 ChannelHandler 进行调用。
ChannelFuture
表示 Channel 中异步 I/O 操作的结果, 在 Netty 中所有的 I/O 操作都是异步的, I/O 的调用会直接返回, 调用者并不能立刻获得结果, 但是可以通过 ChannelFuture 来获取 I/O 操作 的处理状态。
EventLoopGroup 和其实现类 NioEventLoopGroup
EventLoopGroup 是一组 EventLoop 的抽象, Netty 为了更好的利用多核 CPU 资源, 一般 会有多个 EventLoop 同时 工作, 每个 EventLoop 维护着一个 Selector 实例。 EventLoopGroup 提供 next 接口, 可以从组里面按照一定规则 获取其中一个 EventLoop 来处理任务。 在 Netty 服务器端编程中, 我们一般都需要提供两个 EventLoopGroup, 例 如: BossEventLoopGroup 和 WorkerEventLoopGroup。
ServerBootstrap 和 Bootstrap
ServerBootstrap 是 Netty 中的服务器端启动助手,通过它可以完成服务器端的各种配置; Bootstrap 是 Netty 中的客户端启动助手, 通过它可以完成客户端的各种配置。
三,简单实现应用
server端
//1.创建2个线程池对象
//bossGroup 负责接收用户连接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//workGroup 负责处理用户的io读写操作
NioEventLoopGroup workGroup = new NioEventLoopGroup();
//2.创建启动引导类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//3.设置启动引导类
//添加到组中,两个线程池,第一个位置的线程池就负责接收,第二个参数就负责读写
serverBootstrap.group(bossGroup,workGroup)
//给我们当前设置一个通道类型
.channel(NioServerSocketChannel.class)
//绑定一个初始化监听
.childHandler(new ChannelInitializer<NioSocketChannel>() {
//事件监听Channel通道
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
//获取pipeLine
ChannelPipeline pipeline = nioSocketChannel.pipeline();
//绑定编码
pipeline.addFirst(new StringEncoder());
pipeline.addLast(new StringDecoder());
//绑定我们的业务逻辑
pipeline.addLast(new SimpleChannelInboundHandler<String>() {
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
//获取入栈信息,打印客户端传递的数据
System.out.println(msg);
}
});
}
});
//4.启动引导类绑定端口
ChannelFuture future = serverBootstrap.bind(9999).sync();
//5.关闭通道
future.channel().closeFuture().sync();
Client端
//1.创建连接池对象
NioEventLoopGroup group = new NioEventLoopGroup();
//2.创建客户端的启动引导类 BootStrap
Bootstrap bootstrap = new Bootstrap();
//3.配置启动引导类
bootstrap.group(group)
//设置通道为Nio
.channel(NioSocketChannel.class)
//设置Channel初始化监听
.handler(new ChannelInitializer<Channel>() {
//当前该方法监听channel是否初始化
protected void initChannel(Channel channel) throws Exception {
//设置编码
channel.pipeline().addLast(new StringEncoder());
}
});
//4.使用启动引导类连接服务器 , 获取一个channel
Channel channel = bootstrap.connect("127.0.0.1", 9999).channel();
//5.循环写数据给服务器
while (true) {
//给服务器写数据
channel.writeAndFlush("hello server .. this is client ...");
Thread.sleep(2000);
}