介绍Netty的三种模型及其工作原理 , Netty编程Demo
提示:以下是本篇文章正文内容,下面案例可供参考
Reactor模式基本实现
通过一个或多个输入同时传递给服务处理器(ServerHandler)
服务器端的程序会处理传入的多个请求,并将其同步分派到相应的处理线程 (网络服务高并发处理的关键)
reactor模式的核心组成 :
reactor和handler所在的线程是同一个线程
缺点 : 多线程数据共享 , 这比单个线程复杂 ; 单线程reactor处理所有的事件监听响应 , 而且handler也是运行在这单个reactor线程里的 , 在高并发场景容易出现性能瓶颈
相对于单reactor多线程模型 , 主从的方式是将handler从单个reactor中拆分出来了 , 将原先的reactor分成了两层
同时 , 我们的SubReactor是可以由多个的 , subreactor负责处理I/O的读取
netty主要基于主从reactor多线程模型做了改进
编程实例分为客户端和服务器端 , 及其各自的处理器
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
// bossGroup仅处理连接请求
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// workerGroup和客户端做业务处理
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try{
// 创建服务器端启动的对象 , 配置启动参数
ServerBootstrap bootstrap = new ServerBootstrap();
// 链式编程设置参数
bootstrap.group(bossGroup,workerGroup) // 设置两个线程组
.channel(NioServerSocketChannel.class) // 使用NioSctpServerChannel作为服务器的通道实现
.option(ChannelOption.SO_BACKLOG,128) // 设置线程队列得到连接个数
.childOption(ChannelOption.SO_KEEPALIVE,true) // 设置保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() {
// 向pipeline 设置处理器
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 将自定义的处理器加入到管道中
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("服务器就绪");
//绑定一个端口并设置为同步
// 启动服务器
ChannelFuture cf = bootstrap.bind(6666).sync();
// 监听关闭通道事件
cf.channel().closeFuture().sync();
} catch (Exception e){
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
// 自定义一个Handler需要继承netty规定好的HandlerAdapter
public static void main(String[] args) {
}
// 实质上读取数据操作就是在这里做的
/**
* 1. ChannelHandlerContext : 上下文对象,含有 pipeline,channel,连接的地址
* 2. Object : 客户端发送的数据 默认是Object
* */
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server ctx = "+ctx);
// 将msg转成ByteBuf
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发送的消息:"+buf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址"+ctx.channel().remoteAddress());
}
// 数据读取完毕
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 将数据写入到缓存中并刷新
// 需要对发送的数据做编码
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,cli",CharsetUtil.UTF_8));
}
// 发生异常后关闭客户端
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
// 客户端一个事件循环组即可
NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors) // 设置线程组
.channel(NioSocketChannel.class) //设置客户端通道
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端就绪");
// 启动客户端连接服务器
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventExecutors.shutdownGracefully();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
//通道就绪时触发
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client"+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello ,server", CharsetUtil.UTF_8));
}
// 当通道有读取事件时,触发
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务器回复的消息"+buf.toString(CharsetUtil.UTF_8));
System.out.println("服务器地址"+ctx.channel().remoteAddress());
}
//异常处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}