Netty简介
Netty是由jboss提供的一个基于NIO的开源框架。Netty提供异步、基于事件驱动的网络应用程序框架,用于快速开发出高性能、高可靠性的网络IO程序。
Netty模型
上图文解:
1.Netty需要创建两组线程池(NioEventLoopGroup),BossGroup主要负责客户端的请求连接,连接成功后BossGroup会把连接交给 Worker Group,Worker Group负责客户端的读写操作。
2.NioEventLoopGroup可以看作是一个事件循环组,这个组中有多个事件循环,每一个循环事件都是NioEventLoop
3.NioEventLoop不断地循环执行处理任务的线程,每一个NioEventLoop都有一个selector,用于监听绑定在其上的Socket网络通讯
4.NioEventLoopGroup里面包含多个NioEventLoop
5.每个Boss EventLoopGroup循环执行的步骤有三步:
1)轮询客户端access(连接)事件
2)处理access事件,建立连接后生成NioSocketChannel,并注册到某个Worker NioEventLoop上的selector
3)处理任务队列中的任务runAllTasks
6.每个Worker NioEventLoopGroup循环执行的步骤:
1)轮询read/write(读/写)事件
2)在对应的NioSocketChannel中处理读写事件
3)处理任务队列的任务runAllTasks
7.每个worker EventLoop处理业务时,会使用pipeline(管道) ,pipeline中包含了channel,可以获取到对应通道,并维护了很多的处理器
Netty快速入门小案例
案例要求
1)Netty服务器监听6668端口,客户端能发送消息给服务器 " 你好,服务器"
2)服务器回复消息给客户端 "你好,客户端"
导入maven
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>
服务器端代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 入门小案例
* 代码会在后面详解
* */
public class NettyServer1 {
public static void main(String[] args) {
//创建bossGroup和workGroup
//构造函数设置为1个线程运行bossGroup
EventLoopGroup boss = new NioEventLoopGroup(1);
//构造函数为空默认为当前Cpu核心数*2个线程
EventLoopGroup worker = new NioEventLoopGroup();
try{
//serverBootStrap可以理解为用于构建服务器端的核心组件
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boss,worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取到pipeline
ChannelPipeline pipeline = socketChannel.pipeline();
//增加编解码器
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
//增加自己定义的handler,用于接收客户端发送的信息
pipeline.addLast(new NettyServerHandler());
}
});
//绑定端口号并开启服务
ChannelFuture future = serverBootstrap.bind(6668).sync();
//这段代码是阻塞的,并不会立即执行,直到服务器关闭后优雅的退出
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
//优雅的关闭boss和worker(处理完所有请求后会关闭)
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 因为Netty是基于事件处理的
* 所以该类用于读写连接等事件处理的,每一种事件都有不用的处理方法,继承SimpleChannelInboundHandler,泛型为接收的数据类型
* */
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 读取客户端发送的数据
* */
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println("服务器端接收到数据:"+" "+s);
//获取到channel用于回复客户端
Channel channel = channelHandlerContext.channel();
channel.writeAndFlush("你好,客户端");
}
/**
* 发生异常后,关闭客户端连接
* */
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 客户端代码
* */
public class NettyClient1 {
public static void main(String[] args) {
//客户端不需要多个eventLoopGroup
EventLoopGroup group = new NioEventLoopGroup();
try{
//bootStrap可以理解为构建客户端的核心组件,服务器端为serverBootStrap
Bootstrap bootstrap = new Bootstrap();
ChannelFuture future = bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//增加编解码器
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
//增加自定义的handler
pipeline.addLast(new NettyClientHandler());
}
//创建连接
}).connect("127.0.0.1", 6668).sync();
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
//优雅的关闭
group.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 读取服务器返回的消息
* */
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println("接收到服务器消息"+" "+s);
}
/**
* 建立连接后发送信息给服务器
* */
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().writeAndFlush("你好,服务器");
}
}
实现效果
入门案例就完成了,代码会在后面Netty快速入门(四)进行讲解