Netty简介

Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器端网络开发。它是一个NIO框架,对Java NIO进行了良好的封装。作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

Netty的特性

  • 统一的API,适用于不同的协议
  • 基于灵活、可扩展的事件驱动模型
  • 高度可定制的线程模型
  • 更好的吞吐量,低延迟
  • 更省资源,尽量减少不必要的内存拷贝
  • 完整的SSL/TLS和STARTTLS的支持
  • 能在Applet与Android的限制环境运行良好
  • 不再因过快、过慢或超负载连接导致OutOfMemoryError
  • 不再有在高速网络环境下NIO读写频率不一致的问题

Netty核心内容

Netty中最核心的内容主要有以下四个方面:

  • Reactor线程模型:一种高性能的多线程程序设计思路
  • Netty中自己定义的Channel概念:增强版的通道概念
  • ChannelPipeline职责链设计模式:事件处理机制
  • 内存管理:增强的ByteBuf缓冲区

Netty整体结构图

Netty核心组件

EventLoop:EventLoop维护了一个线程和任务队列,支持异步提交执行任务。EventLoop自身实现了Executor接口,当调用executor方法提交任务时,则判断是否启动,未启动则调用内置的executor创建新线程来触发run方法执行,其大致流程参考Netty源码SingleThreadEventExecutor如下:

EventLoopGroup: EventLoopGroup主要是管理eventLoop的生命周期,可以将其看作是一个线程池,其内部维护了一组EventLoop,每个eventLoop对应处理多个Channel,而一个Channel只能对应一个EventLoop

Bootstrap:BootStrap 是客户端的引导类,主要用于客户端连接远程主机,有1个EventLoopGroup。Bootstrap 在调用 bind()(连接UDP)和 connect()(连接TCP)方法时,会新创建一个单独的、没有父 Channel 的 Channel 来实现所有的网络交换。

ServerBootstrap: ServerBootstrap 是服务端的引导类,主要用户服务端绑定本地端口,有2个EventLoopGroup。ServerBootstarp 在调用 bind() 方法时会创建一个 ServerChannel 来接受来自客户端的连接,并且该 ServerChannel 管理了多个子 Channel 用于同客户端之间的通信。

Channel:Netty中的Channel是一个抽象的概念,可以理解为对Java NIO Channel的增强和扩展,增加了许多新的属性和方法,如bing方法等。

ChannelFuture:ChannelFuture能够注册一个或者多个ChannelFutureListener 实例,当操作完成时,不管成功还是失败,均会被通知。ChannelFuture存储了之后执行的操作的结果并且无法预测操作何时被执行,提交至Channel的操作按照被唤醒的顺序被执行。

ChannelHandler:ChannelHandler用来处理业务逻辑,分别有入站和出站的实现。

ChannelPipeline: ChannelPipeline 提供了 ChannelHandler链的容器,并定义了用于在该链上传播入站和出站事件流的API。

Netty线程模型

Netty的线程模型是基于Reactor模式的线程实现。关于Reactor模式可以参考 Reactor模式 ,Netty中依据用户的配置可以支持单线程的Reactor模型,多线程的Reactor模型以及主从多Reactor的模型。在Netty中其大致流程如下如下:

Netty入门代码示例

服务端代码示例:

  1. import io.netty.bootstrap.ServerBootstrap;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.*;
  5. import io.netty.channel.nio.NioEventLoopGroup;
  6. import io.netty.channel.socket.SocketChannel;
  7. import io.netty.channel.socket.nio.NioServerSocketChannel;
  8. import io.netty.handler.logging.LogLevel;
  9. import io.netty.handler.logging.LoggingHandler;
  10. import java.nio.charset.Charset;
  11. public class EchoServer {
  12. public static void main(String[] args) {
  13. // accept线程组,用来接受连接
  14. EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  15. // I/O线程组, 用于处理业务逻辑
  16. EventLoopGroup workerGroup = new NioEventLoopGroup(1);
  17. try {
  18. // 服务端启动引导
  19. ServerBootstrap b = new ServerBootstrap();
  20. b.group(bossGroup, workerGroup) // 绑定两个线程组
  21. .channel(NioServerSocketChannel.class) // 指定通道类型
  22. .option(ChannelOption.SO_BACKLOG, 100) // 设置TCP连接的缓冲区
  23. .handler(new LoggingHandler(LogLevel.INFO)) // 设置日志级别
  24. .childHandler(
  25. new ChannelInitializer<SocketChannel>() {
  26. @Override
  27. protected void initChannel(SocketChannel socketChannel) throws Exception {
  28. ChannelPipeline pipeline = socketChannel.pipeline(); // 获取处理器链
  29. pipeline.addLast(new EchoServerHandler()); // 添加新的件处理器
  30. }
  31. });
  32. // 通过bind启动服务
  33. ChannelFuture f = b.bind(8080).sync();
  34. // 阻塞主线程,知道网络服务被关闭
  35. f.channel().closeFuture().sync();
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. } finally {
  39. workerGroup.shutdownGracefully();
  40. bossGroup.shutdownGracefully();
  41. }
  42. }
  43. }
  44. class EchoServerHandler extends ChannelInboundHandlerAdapter {
  45. // 每当从客户端收到新的数据时,这个方法会在收到消息时被调用
  46. @Override
  47. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  48. System.out.println("收到数据:" + ((ByteBuf) msg).toString(Charset.defaultCharset()));
  49. ctx.write(Unpooled.wrappedBuffer("Server message".getBytes()));
  50. ctx.fireChannelRead(msg);
  51. }
  52. // 数据读取完后被调用
  53. @Override
  54. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  55. ctx.flush();
  56. }
  57. // 当Netty由于IO错误或者处理器在处理事件时抛出的异常时被调用
  58. @Override
  59. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  60. cause.printStackTrace();
  61. ctx.close();
  62. }
  63. }

客户端代码示例:

  1. import io.netty.bootstrap.Bootstrap;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.*;
  5. import io.netty.channel.nio.NioEventLoopGroup;
  6. import io.netty.channel.socket.SocketChannel;
  7. import io.netty.channel.socket.nio.NioSocketChannel;
  8. import java.nio.charset.Charset;
  9. public class EchoClient {
  10. public static void main(String[] args) {
  11. EventLoopGroup group = new NioEventLoopGroup();
  12. try {
  13. Bootstrap b = new Bootstrap();
  14. b.group(group)
  15. .channel(NioSocketChannel.class)
  16. .option(ChannelOption.TCP_NODELAY, true)
  17. .handler(
  18. new ChannelInitializer<SocketChannel>() {
  19. @Override
  20. public void initChannel(SocketChannel ch) throws Exception {
  21. ChannelPipeline p = ch.pipeline();
  22. p.addLast(new EchoClientHandler());
  23. }
  24. });
  25. ChannelFuture f = b.connect("127.0.0.1", 8080).sync();
  26. f.channel().closeFuture().sync();
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. } finally {
  30. group.shutdownGracefully();
  31. }
  32. }
  33. }
  34. class EchoClientHandler extends ChannelInboundHandlerAdapter {
  35. private final ByteBuf firstMessage;
  36. public EchoClientHandler() {
  37. firstMessage = Unpooled.buffer(256);
  38. for (int i = 0; i < firstMessage.capacity(); i++) {
  39. firstMessage.writeByte((byte) i);
  40. }
  41. }
  42. @Override
  43. public void channelActive(ChannelHandlerContext ctx) {
  44. ctx.writeAndFlush(firstMessage);
  45. }
  46. @Override
  47. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  48. System.out.println("收到数据:" + ((ByteBuf) msg).toString(Charset.defaultCharset()));
  49. ctx.write(Unpooled.wrappedBuffer("Client message".getBytes()));
  50. }
  51. @Override
  52. public void channelReadComplete(ChannelHandlerContext ctx) {
  53. ctx.flush();
  54. }
  55. @Override
  56. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  57. cause.printStackTrace();
  58. ctx.close();
  59. }
  60. }

Java网络编程 -- Netty入门的更多相关文章

  1. 网络编程Netty入门:Netty简介及其特性

    目录 Netty的简介 Netty的特性 Netty的整体结构 Netty的核心组件 Netty的线程模型 结束语 Netty的简介 Netty是一个java开源框架,是基于NIO的高性能.高可扩展性 ...

  2. Java网络编程--Netty中的责任链

    Netty中的责任链 设计模式 - 责任链模式 责任链模式(Chain of Responsibility Pattern)是一种是行为型设计模式,它为请求创建了一个处理对象的链.其链中每一个节点都看 ...

  3. Java网络编程 -- Netty中的ByteBuf

    由于JDK中提供的ByteBuffer无法动态扩容,并且API使用复杂等原因,Netty中提供了ByteBuf.Bytebuf的API操作更加便捷,可以动态扩容,提供了多种ByteBuf的实现,以及高 ...

  4. Java网络编程从入门到精通(27):关闭服务端连接

    在客户端和服务端的数据交互完成后,一般需要关闭网络连接.对于服务端来说,需要关闭Socket和ServerSocket. 在关闭Socket后,客户端并不会马上感知自已的Socket已经关闭,也就是说 ...

  5. 网络编程Netty入门:Netty的启动过程分析

    目录 Netty的启动过程 Bootstrap 服务端的启动 客户端的启动 TCP粘包.拆包 图示 简单的例子 Netty编解码框架 Netty解码器 ByteToMessageDecoder实现类 ...

  6. 网络编程Netty入门:ByteBuf分析

    目录 Netty中的ByteBuf优势 NIO使用的ByteBuffer有哪些缺点 ByteBuf的优势和做了哪些增强 ByteBuf操作示例 ByteBuf操作 简单的Demo示例 堆内和堆外内存 ...

  7. 网络编程Netty入门:EventLoopGroup分析

    目录 Netty线程模型 代码示例 NioEventLoopGroup初始化过程 NioEventLoopGroup启动过程 channel的初始化过程 Netty线程模型 Netty实现了React ...

  8. 网络编程Netty入门:责任链模式介绍

    目录 责任链模式 责任链模式的简单实现 Netty中的ChannelPipeline责任链 服务端接收客户端连接 pipeline初始化 入站事件和出站事件 Pipeline中的Handler Pip ...

  9. 【Java】Java网络编程菜鸟进阶:TCP和套接字入门

    Java网络编程菜鸟进阶:TCP和套接字入门 JDK 提供了对 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protoco ...

随机推荐

  1. Kafka消息队列初识

    一.Kafka简介 1.1 什么是kafka kafka是一个分布式.高吞吐量.高扩展性的消息队列系统.kafka最初是由Linkedin公司开发的,后来在2010年贡献给了Apache基金会,成为了 ...

  2. 有趣的RPC理解

    RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通 ...

  3. SpringBoot:Web开发

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 , 基于atguigu 1.5.x 视频优化 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处 ...

  4. Java.基础 -------- 一个Java源文件中可以有很多类,但只能有一个类是public的

    一个Java源文件中可以有很多类,但只能有一个类是public的        Java程序是从一个public类main函数开始执行的,只能有一个public是为了给类装载器提供方便,一个publi ...

  5. Java Web基础面试题整理

    Tomcat的缺省端口是多少,怎么修改 tomcat默认缺省端口是8080 修改方法: 找到Tomcat目录下的conf文件夹 进入conf文件夹里面找到server.xml文件 打开server.x ...

  6. 发布一个自己的jar包给全球人使用

    目录 项目准备 sonatype 注册 申请sonatype工单 gpg配置 项目配置 依赖oss-parent 自定义配置 pom配置 全局settings配置 发布 验证 maven 项目对于我们 ...

  7. Linux--shell重定向与文件处理命令--02

    一.IO重定向 1.数据输入:键盘---标准输入,但并不是唯一输入方式 ” | passwd –stdin username #同时添加用户和密码 while line;do 循环体...$line ...

  8. Spring入门(九):运行时值注入

    Spring提供了2种方式在运行时注入值: 属性占位符(Property placeholder) Spring表达式语言(SpEL) 1. 属性占位符 1.1 注入外部的值 1.1.1 使用Envi ...

  9. win10 将硬盘工作模式由IDE调整到AHCI模式

    第1步:重启进入安全模式 1)点击“开始”按钮 进入设置 2)进入“更新和安全”,“恢复-高级启动”,点击“立即高级启动”, 依次选择“疑难解答”-“高级选项”-“启动设置”-点击“重启” 第2步:进 ...

  10. Kafka之Producer

    通过https://www.cnblogs.com/tree1123/p/11243668.html 已经对consumer有了一定的了解.producer比consumer要简单一些. 一.旧版本p ...