Netty 权威指南笔记(二):Java NIO 和 Netty 对比
来源:互联网 发布:php 捕获异常 编辑:程序博客网 时间:2024/05/29 08:34
- Netty 权威指南笔记二Java NIO 和 Netty 对比
- Java NIO 开发
- Netty 开发
- 示例程序
Netty 权威指南笔记(二):Java NIO 和 Netty 对比
Netty 是业界流行的 NIO 框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都说首屈一指的,也已经得到了成百上千商用项目的验证。Netty 框架都有什么优点呢?
- API 使用简单,开发门槛低。
- 功能强大,预置多种编解码功能,支持多种主流协议。
- 定制能力强,可以通过 ChannelHandler 对通信框架灵活扩展。
- 性能高。
- 成熟稳定,社区活跃,已经修复了 Java NIO 所有的 Bug。
- 经历了大规模商业应用的考验,质量有保证。
Java NIO 开发
我们看一看在 笔记(一)里面的 Java NIO 示例程序,回顾一下使用 NIO 开发服务端程序的步骤:
- 创建 ServerSocketChannel 和业务处理线程池。
- 绑定监听端口,并配置为非阻塞模式。
- 创建 Selector,将之前创建的 ServerSocketChannel 注册到 Selector 上,监听 SelectionKey.OP_ACCEPT。
- 循环执行 Selector.select() 方法,轮询就绪的 Channel。
- 轮询就绪的 Channel 时,如果是处于 OP_ACCEPT 状态,说明是新的客户端接入,调用 ServerSocketChannel.accept 接收新的客户端。
- 设置新接入的 SocketChannel 为非阻塞模式,并注册到 Selector 上,监听 OP_READ。
- 如果轮询的 Channel 状态是 OP_READ,说明有新的就绪数据包需要读取,则构造 ByteBuffer 对象,读取数据。
Netty 开发
在讲 Netty 优点的时候,说到“Netty API 使用简单,开发门槛低”。先看看下面的 Netty TimeServer 示例程序,看看 Netty 开发都有哪些步骤?
- 创建 NIO 线程组 EventLoopGroup 和 ServerBootstrap。
- 设置 ServerBootstrap 的属性:线程组、SO_BACKLOG 选项,设置 NioServerSocketChannel 为 Channel,设置业务处理 Handler。
- 绑定端口,启动服务器程序。
- 在业务处理 TimeServerHandler 中,读取客户端发送的数据,并给出响应。
那么相比 Java NIO,使用 Netty 开发程序,都简化了哪些步骤呢?
- OP_ACCEPT 的处理被简化,因为对于 accept 操作的处理在不同业务上都是一致的。
- 在 NIO 中需要自己构建 ByteBuffer 从 Channel 中读取数据,而 Netty 中数据是直接读取完成存放在 ByteBuf 中的。相当于省略了用户进程从内核中复制数据的过程。
- 在 Netty 中,我们看到有使用一个解码器 FixedLengthFrameDecoder,可以用于处理定长消息的问题,能够解决 TCP 粘包读半包问题,十分方便。
示例程序
服务器端程序
public class TimeServer { public void bind(int port) throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 2014) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(16)); socketChannel.pipeline().addLast(new TimeServerHandler()); } }); ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("start listening ..."); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { int port = 11000; new TimeServer().bind(port); }}
TimeServerHandler 业务处理类:
public class TimeServerHandler extends ChannelHandlerAdapter { private int counter = 0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "UTF-8"); System.out.println("time server receive: " + body + ", counter: " + counter++); String currentTime = "QUERY TIME ORDER".equals(body) ? new Date().toString() : "BADY ORDER"; ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes()); ctx.write(resp); } /** * 读完一批次数据,就会调用一次 channelReadComplete * @param ctx * @throws Exception */ @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { System.out.println("channelReadComplete"); // flush 之后,之前 write 的数据,才会发送出去 ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("exceptionCaught"); cause.printStackTrace(); ctx.close(); }}
客户端程序
public class TimeClient { public void connect(int port, String host) throws InterruptedException { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { List<VirtualMachineDescriptor> list = VirtualMachine.list(); for (VirtualMachineDescriptor descriptor : list) { System.out.println(descriptor.displayName()); } System.out.println("vm: " + list.size()); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(28)); socketChannel.pipeline().addLast(new TimeClientHandler()); } }); ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); channelFuture.channel().closeFuture().sync(); System.out.println("end listening ..."); } finally { eventLoopGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { int port = 11000; new TimeClient().connect(port, "127.0.0.1"); }}
TimeClientHandler 客户端业务处理类:
public class TimeClientHandler extends ChannelHandlerAdapter { private final byte[] req; private int counter = 0; public TimeClientHandler() { System.out.println("init TimeClientHandler"); req = "QUERY TIME ORDER".getBytes(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i = 0; i < 100; ++i) { ByteBuf firstMessage = Unpooled.buffer(req.length); firstMessage.writeBytes(req); ctx.writeAndFlush(firstMessage); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("channelRead"); ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); System.out.println("now is: " + new String(req, "UTF-8") + ", counter: " + counter++); if (counter > 99) { ctx.close(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("exceptionCaught"); ctx.close(); }}
阅读全文
0 0
- Netty 权威指南笔记(二):Java NIO 和 Netty 对比
- Netty 权威指南笔记(一):网络 I/O 模型和 Java NIO 入门
- Netty权威指南(笔记二)
- Netty权威指南读书笔记(二)
- Netty 权威指南笔记(八):EventLoopGroup 和线程模型
- Netty权威指南(笔记一)
- 《Netty权威指南》基础篇--走进Java NIO
- Java互联网架构Netty、Nio、Mina权威指南
- Netty权威指南 第2版学习笔记3——Netty NIO开发指南
- 《netty权威指南》2.3 NIO编程
- Netty权威指南之NIO入门
- Netty 权威指南笔记(四):架构剖析
- Netty 权威指南笔记(五):ByteBuf 源码解读
- Netty 权威指南笔记(六):Channel 解读
- Netty权威指南学习笔记1
- 《netty权威指南》学习笔记1
- 《netty权威指南》学习笔记2
- netty权威指南 学习笔记http
- 视图与委托
- python type() 判断数据类型
- python *
- jQuery事件冒泡
- The Multiresolution Toolkit: Progressive Access for Regular Gridded Data
- Netty 权威指南笔记(二):Java NIO 和 Netty 对比
- scikit-learn Adaboost类库使用小结
- Cesium中的几种坐标和相互转换
- 队列的基本操作(简单版)
- 消息摘要算法-HMAC算法
- mysql常用命令
- 砖块伺服器和完全标准化至边缘
- editplus 一键运行任意可执行脚本
- 装饰器模式