本文参考

我在博客内关于"Netty学习摘记"的系列文章主要是对《Netty in action》一书的学习摘记,文章中的代码也大多来自此书的github仓库,加上了一部分我自己的注释内容。之所以开始对Netty的学习,是因为在高并发网络编程和大数据生态圈都有它活跃的身影,例如Cassandra、ElasticSearch、Spark和ZooKeeper中就有Netty框架的应用,便对它产生了兴趣,若要再说的实际一点,面试官也很有可能问网络高并发和关于netty的东东呢

本篇文章是对此书第一章"Netty —— 异步和事件驱动"的学习摘记,主要内容为Java网络编程简介、Netty简介和Netty的核心组件

阻塞IO

我们需要为每一个接入的用户创建一个新的线程,并且程序中存在阻塞线程的代码段,使得大量的线程处于空闲状态,没有在实际处理用户的请求,因而引起资源的浪费,显然无法支持大并发量的连接

public void serve(int portNumber) throws IOException {

  //创建一个新的 ServerSocket,用以监听指定端口上的连接请求

  ServerSocket serverSocket = new ServerSocket(portNumber);

  //accept()方法的调用将被阻塞,直到一个连接建立

  Socket clientSocket = serverSocket.accept();

  //这些流对象都派生于该套接字的流对象

  BufferedReader in = new BufferedReader(

    new InputStreamReader(clientSocket.getInputStream()));

  PrintWriter out =

    new PrintWriter(clientSocket.getOutputStream(), true);

  String request, response;

  //处理循环开始,阻塞,直到由换行符或者回车符结尾的字符串被读取

  while ((request = in.readLine()) != null) {

    if ("Done".equals(request)) {

      break;
    }

    //请求被传递给服务器的处理方法

    response = processRequest(request);

    //服务器的响应被发送给了客户端

    out.println(response);

    //继续执行处理循环

  }
}

private String processRequest(String request){

  return "Processed";
}

非阻塞IO(NIO)

选择器 java.nio.channels.Selector 使用了事件通知 API 以确定在一组非阻塞套接字中有哪些已经就绪能够进行 I/O 相关的操作。因为可以在任何的时间检查任意的读操作或者写操作的完成状态,因此一个单一的线程便可以处理多个并发的连接,即能够通过较少的线程便可监视许多连接上的事件,这种模型减少了内存管理和上下文切换所带来开销,并且当没有 I/O 操作需要处理的时候,线程也可以被用于其他任务

在Netty中EventLoop扮演了这一角色,并简化了事件的接收和派发过程

Netty基本定义

Netty 是一款异步(构建在非阻塞的基础上)的事件驱动的网络应用程序框架,实现业务和网络逻辑解耦,支持快速地开发可维护的高性能的面向协议的服务器和客户端

Netty的核心组件

Channel:

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作

可以把Channel看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接

回调:

回调能够在某项操作完成后进行通知,它可以和ChannelFuture相互补充,下例是一个新的连接被建立时的回调方法channelActive(),它也代表一个连接被激活的事件

public class ConnectHandler extends ChannelInboundHandlerAdapter {

  @Override

  //当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用

  public void channelActive(ChannelHandlerContext ctx) throws Exception {

    System.out.println("Client " + ctx.channel().remoteAddress() + " connected");
  }
}

Future:

Future提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操 作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问

ChannelFuture:

ChannelFuture是Future的子接口,提供了几种额外的方法使得我们能够注册一个或者多个 ChannelFutureListener实例,ChannelFutureListener 可以看作是回调的一个更加精细的版本。监听器的回调方法operationComplete(),将会在对应的操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了,如下例中的isSuccess()方法。如果是后者,我们可以检索产生的Throwable,并打印错误信息

连接远程节点和出站 I/O 操作都将返回一个ChannelFuture,它们都不会阻塞,如下例中的connect()方法连接远程节点和writeAndFlush()方法向远程推送数据时,能够返回一个ChannelFuture

public static void connect() {

  Channel channel = new NioSocketChannel();

  //异步非阻塞地连接到远程节点

  ChannelFuture future = channel.connect(

    new InetSocketAddress("192.168.0.1", 25));

  //注册一个 ChannelFutureListener,以便在操作完成时获得通知

  future.addListener(new ChannelFutureListener() {

    @Override

    public void operationComplete(ChannelFuture future) {

      //检查操作的状态

      if (future.isSuccess()) {

        //如果操作是成功的,则创建一个 ByteBuf 以持有数据

        ByteBuf buffer = Unpooled.copiedBuffer( "Hello", Charset.defaultCharset());

        //将数据异步地发送到远程节点。返回一个 ChannelFuture

        ChannelFuture
wf = future.channel().writeAndFlush(buffer);

        // ...

      } else {

        //如果发生错误,则访问描述原因的 Throwable

        Throwable cause = future.cause();

        cause.printStackTrace();
      }
    }
  });
}

事件、EventLoop和ChannelHandler:

Netty 通过触发事件将 Selector 从应用程序中抽象出来,消除了所有本来将需要手动编写的派发代码。Netty为每个 Channel 分配一个 由单线程驱动的EventLoop来处理所有I/O事件,包括注册感兴趣的事件、将事件派发给 ChannelHandler和安排进一步的动作

由入站数据或者相关的状态更改而触发的事件:连接已被激活或者连接失活、数据读取、用户事件和错误事件等

而出站事件是未来将会触发的某个动作的操作结果:打开或者关闭到远程节点的连接、将数据写到或者冲刷到套接字等

 

最新文章

  1. git 命令
  2. Ubuntu1604下安装Liggghts及CFDEM Coupling
  3. CSS3 图片悬浮缩放效果
  4. Java Script基础(十一) 表单验证
  5. OC - 8.Quartz2D核心要点
  6. hdu5360 Hiking(水题)
  7. Android ListView A~Z快速索引(改进版)
  8. 【每天一个Linux命令】12. Linux中which命令的用法
  9. ST 单元测试之maven引入junit包
  10. php多个文件上传
  11. 用原生js实现一个new方法
  12. 如何加入Microsoft Teams 技术社区
  13. js将文字转化为语音并播放
  14. nethogs 查看linux进程实时网络带宽利用率
  15. pip install Yellowfin失败的问题
  16. PHPExcel使用-使用PHPExcel导出文件
  17. springboot之约定大约配置
  18. sql 去重关键字 distinct
  19. CentOS 下 SonarQube 6.7 的下载、配置、问题排查
  20. gdb调试器学习链接

热门文章

  1. Hook(钩子技术)基本知识讲解,原理
  2. JAVA只要掌握内部类,多继承和单继承都不是问题
  3. 『无为则无心』Python日志 — 65、日志模块logging的使用
  4. 鼠标点击的时候出现 "双心心" 的效果
  5. Python:PIL(三)——Image
  6. Chrome:开发者模式下选取网页元素对应的代码
  7. Mysql的用户管理与授权
  8. 『现学现忘』Docker相关概念 — 1、云计算概念
  9. TP5框架中实现多条件登录(自写代码,密码未md5()加密)
  10. OpenSSL CVE-2022-0778漏洞问题复现与非法证书构造