Netty 入门初体验

Stella981
• 阅读 581

Netty简介

Netty是一款异步的事件驱动的网络应用程序框架,支持快速开发可维护的高性能的面向协议的服务器和客户端。Netty主要是对java 的 nio包进行的封装

为什么要使用 Netty

上面介绍到 Netty是一款 高性能的网络通讯框架,那么我们为什么要使用Netty,换句话说,Netty有哪些优点让我们值得使用它,为什么不使用原生的 Java Socket编程,或者使用 Java 1.4引入的 Java NIO。接下来分析分析 Java Socket编程和 Java NIO。

Java 网络编程

首先来看一个Java 网络编程的例子:

public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(8888); Socket socket = serverSocket.accept(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.println("received: " + line); } } catch (IOException e) { e.printStackTrace(); } } 复制代码

上面展示了一个简单的Socket服务端例子,该代码只能同时处理一个连接,要管理多个并发客户端,需要为每个新的客户端Socket创建一个 新的Thread。这种并发方案对于中小数量的客户端来说还可以接受,如果是针对高并发,超过100000的并发连接来说该方案并不可取,它所需要的线程资源太多,而且任何时候都可能存在大量线程处于阻塞状态,等待输入或者输出数据就绪,整个方案性能太差。所以,高并发的场景,一般的Java 网络编程方案是不可取的。

Java NIO

还是先来看一个 Java NIO的例子:

public class ServerSocketChannelDemo {
    private ServerSocketChannel serverSocketChannel; private Selector selector; public ServerSocketChannelDemo(int port) throws IOException { serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(port)); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void listener() throws IOException { while (true) { int n = selector.select(); if (n == 0) { continue; } Iterator iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = (SelectionKey) iterator.next(); if (selectionKey.isAcceptable()) { ServerSocketChannel server_channel = (ServerSocketChannel) selectionKey.channel(); SocketChannel socketChannel = server_channel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } if (selectionKey.isReadable()) { //如果通道处于读就绪的状态 //读操作 //TODO } } } } } 复制代码

NIO的核心部分主要有:

  • 通道 Channel
  • 缓冲区 Buffer
  • 多路复用器 Selector

选择器 Selector 是 Java 非阻塞 I/O实现的关键,将通道Channel注册在 Selector上,如果某个通道 Channel发送 读或写事件,这个Channel处于就绪状态,会被Selector轮询出来,进而进行后续I/O操作。这种I/O多路复用的方式相比上面的阻塞 I/O模型,提供了更好的资源管理:

  • 使用较少的线程便可以处理很多连接,因此也减少了内存管理和上下文切换所带来的开销
  • 当没有I/O操作需要处理的时候,线程也可以被用于其他任务。

尽管使用 Java NIO可以让我们使用较少的线程处理很多连接,但是在高负载下可靠和高效地处理和调度I/O操作是一项繁琐而且容易出错的任务,所以才引出了高性能网络编程专家——Netty

Netty特性

Netty有很多优秀的特性值得让我们去使用它(摘自《Netty实战》):

设计

  • 统一的API,适用于不同的协议(阻塞和非阻塞)
  • 基于灵活、可扩展的事件驱动模型
  • 高度可定制的线程模型
  • 可靠的无连接数据Socket支持(UDP)

性能

  • 更好的吞吐量,低延迟
  • 更低的资源消耗
  • 最少的内存复制

健壮性

  • 不再因过快、过慢或超负载连接导致OutOfMemoryError
  • 不再有在高速网络环境下NIO读写频率不一致的问题

安全性

  • 完整的SSL/TLS和STARTTLS的支持
  • 可用于受限环境下,如 Applet 和OSGI

易用

  • 详实的Javadoc和大量的示例集
  • 不需要超过 JDK 1.6+的依赖

Netty示例代码

下面是server 和client的示例代码,先来看看Netty代码是怎么样的,后续文章会详细分析各个模块。

Server代码

public class EchoServer {
    private final int port; public EchoServer(int port) { this.port = port; } public static void main(String[] args) throws InterruptedException { new EchoServer(8888).start(); } public void start() throws InterruptedException { final EchoServerHandler serverHandler = new EchoServerHandler(); //创建EventLoopGroup,处理事件 EventLoopGroup boss = new NioEventLoopGroup(); EventLoopGroup worker = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(boss,worker) //指定所使用的NIO传输 Channel .channel(NioServerSocketChannel.class) //使用指定的端口设置套接字地址 .localAddress(new InetSocketAddress(port)) //添加一个EchoServerHandler到子Channel的ChannelPipeline .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //EchoServerHandler标志为@Shareable,所以我们可以总是使用同样的实例 socketChannel.pipeline().addLast(serverHandler); } }); //异步的绑定服务器,调用sync()方法阻塞等待直到绑定完成 ChannelFuture future = b.bind().sync(); future.channel().closeFuture().sync(); } finally { //关闭EventLoopGroup,释放所有的资源 group.shutdownGracefully().sync(); worker.shutdownGracefully().sync(); } } } 复制代码

EchoServerHandler

@ChannelHandler.Sharable //标识一个 ChannelHandler可以被多个Channel安全地共享
public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buffer = (ByteBuf) msg; //将消息记录到控制台 System.out.println("Server received: " + buffer.toString(CharsetUtil.UTF_8)); //将接受到消息回写给发送者 ctx.write(buffer); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //将未消息冲刷到远程节点,并且关闭该 Channel ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) .addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { //打印异常栈跟踪 cause.printStackTrace(); //关闭该Channel ctx.close(); } } 复制代码

代码要点解读:

  • ServerBootStrap是引导类,帮助服务启动的辅助类,可以设置 Socket参数
  • EventLoopGroup是处理I/O操作的线程池,用来分配 服务于Channel的I/O和事件的 EventLoop,而NioEventLoopGroupEventLoopGroup的一个实现类。这里实例化了两个 NioEventLoopGroup,一个 boss,主要用于处理客户端连接,一个 worker用于处理客户端的数据读写工作
  • EchoServerHandler实现了业务逻辑
  • 通过调用ServerBootStrap.bind()方法以绑定服务器

Client 代码

public class EchoClient {
    private final String host; private final int port; public EchoClient(String host, int port) { this.host = host; this.port = port; } public void start() throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .remoteAddress(new InetSocketAddress(host, port)) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture channelFuture = b.connect().sync(); channelFuture.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); } } public static void main(String[] args) throws InterruptedException { new EchoClient("127.0.0.1", 8888).start(); } } 复制代码

EchoClientHandler

@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { System.out.println("Client received: "+byteBuf.toString()); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks",CharsetUtil.UTF_8)); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 复制代码

代码要点解读:

  • 为初始化客户端,创建了一个BootStrap实例,与ServerBootStrap一样,也是一个引导类,主要辅助客户端
  • 分配了一个 NioEventLoopGroup实例,里面的 EventLoop,处理连接的生命周期中所发生的事件
  • EchoClientHandler类负责处理业务逻辑,与服务端的EchoSeverHandler作用相似。

参考资料 & 鸣谢

作者:pjmike_pj
链接:https://juejin.im/post/5ba35a76f265da0a951ed4db

点赞
收藏
评论区
推荐文章
威尔we 威尔we
3年前
Netty 高性能网络协议服务器开发
本文通过一个实例来讲解如何使用框架来开发网络协议服务器,项目使用工具来构建和运行,并且支持部署。项目代码已在GitHub开源,。Netty简介Netty是一个异步、事件驱动的网络应用框架,使用它可以快速开发出可维护良好的、高性能的网络协议服务器。它大幅简化和流程化了网络编程,比如TCP和UDP套接字服务器开发。难能
京东云开发者 京东云开发者
11个月前
Netty服务端开发及性能优化 | 京东云技术团队
Netty是一个异步基于事件驱动的高性能网络通信框架,可以看做是对NIO和BIO的封装,并提供了简单易用的API、Handler和工具类等,用以快速开发高性能、高可靠性的网络服务端和客户端程序。
Stella981 Stella981
2年前
Netty序章之BIO NIO AIO演变
Netty序章之BIONIOAIO演变Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能、高可靠的网络服务器和客户端程序。Netty简化了网络程序的开发,是很多框架和公司都在使用的技术。更是面试的加分项。Netty并非横空出世,它是在BIO,NIO,AIO演变中的产物,是一种
Stella981 Stella981
2年前
BIO、NIO、AIO系列二:Netty
一、概述Netty是一个Java的开源框架。提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty是一个NIO客户端,服务端框架。允许快速简单的开发网络应用程序。例如:服务端和客户端之间的协议,它简化了网络编程规范。二、NIO开发的问题
Stella981 Stella981
2年前
Netty精粹之设计更快的ThreadLocal
Netty是一款优秀的开源的NIO框架,其异步的、基于IO事件驱动的设计以及简易使用的API使得用户快速构建基于NIO的高性能高可靠性的网络服务器成为可能。Netty除了使用Reactor设计模式加上精心设计的线程模型之外,对于线程创建的具体细节也进行了重新设计,由于Netty的应用场景主要面向高并发高负载的场景下,这也是Netty能够大显身手的场景,因此,
Stella981 Stella981
2年前
Netty 入门,这一篇文章就够了
Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo、Rocketmq、Hadoop等,针对高性能RPC,一般都是基于Netty来构建,比如sockbolt。总之一句话,Java小伙伴们需要且有必要学会使用Netty并理解其实现原理。netty旨在为可维护的高性能、高可扩展
Stella981 Stella981
2年前
Netty网络编程(初识)
Netty简单介绍核心架构图(现在还看不是很懂):!netty(https://static.oschina.net/uploads/img/201712/02192156_X1e5.png"netty")Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高
Stella981 Stella981
2年前
Netty(RPC高性能之道)原理剖析
1,Netty简述Netty是一个基于JAVANIO类库的异步通信框架,用于创建异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性的网络客户端和服务器端RPC高性能分析,请参考文章“【总结】RPC性能之道”特点异步、非阻塞、基于事件驱动的NIO框架支持多种传输层通信协议,包括T
Stella981 Stella981
2年前
Netty入门
一、是什么  Netty是一个高性能、异步事件驱动、基于JavaNIO的异步的可扩展的客户端/服务器网络编程框架。  Netty提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过FutureListener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果
Stella981 Stella981
2年前
Netty堆外内存泄露排查与总结
导读Netty是一个异步事件驱动的网络通信层框架,用于快速开发高可用高性能的服务端网络框架与客户端程序,它极大地简化了TCP和UDP套接字服务器等网络编程。Netty底层基于JDK的NIO,我们为什么不直接基于JDK的NIO或者其他NIO框架:1.使用JDK自带的NIO需要了解太多的概念,编程复杂。2