《Netty权威指南》(二)NIO 入门

[TOC]java

 

2.1 同步阻塞 I/O

采用 BIO 通讯模型的服务器,一般由一个独立的 Acceptor 线程负责监听客户端的链接,它接收到客户端链接请求以后为每一个客户端建立一个新的线程进行处理,处理完成后,经过输出流返回应答给客户端,线程销毁。编程

graph TD A1[Socket] -->|读/写| B(Acceptor 线程) A2[Socket] -->|读/写| B A3[Socket] -->|读/写| B B -->|建立| C1[Thread] B -->|建立| C2[Thread] B -->|建立| C3[Thread]

 

2.2 伪异步 I/O

采用 线程池任务队列 能够实现一种叫作 伪异步 I/O 通讯框架。 当有新的客户端接入时,将客户端的 Socket 封装成一个 Task 投递到后端的线程池中进行处理,JDK 的线程池维护着一个消息队列和 N 个活跃线程,对消息队列中的任务进行处理。因为线程池能够设置消息队列的大小和最大线程数,所以它的资源占用时可控的,不管多少个客户端并发访问,都不会致使资源的耗尽和宕机。后端

graph TD A1[Socket] -->|读/写| B(Acceptor 线程) A2[Socket] -->|读/写| B A3[Socket] -->|读/写| B B --> |提交 Task|P[Thread Pool] B --> |提交 Task|P B --> |提交 Task|P

 

2.3 NIO

NIO 官方称为 New I/O,目标是要让 Java 支持非阻塞 I/O,因此一般也叫非阻塞 I/O(Non-blocking I/O)。api

阻塞模式使用很是简单,可是性能和可靠性都很差,非阻塞模式则正好相反。通常来讲,低负载、低并发的应用程序能够选择同步阻塞 I/O 以下降编程复杂度;对于高负载、高并发的网络应用,须要使用 NIO 的非阻塞模式进行开发。安全

graph TD A1[Socket] -->|读/写| B(Selector) A2[Socket] -->|读/写| B A3[Socket] -->|读/写| B B --> P[Thread]

2.3.1 Buffer、Channel、Selector

1. 缓冲区 Buffer

Buffer 是一个对象,它包含一些要写入或者要读出的数据。在 NIO 库中,全部数据都是用缓冲区处理的。在读取数据时,它是直接从缓冲区读取;在写入数据时,写入到缓冲区。服务器

2. 通道 Channel

网络数据经过 Channel 读取和写入。通道与流的不一样之处在于通道是双向的,流只是在一个方向移动,而通道可用于读、写或者两者同时进行。网络

由于 Channel 是全双工的,因此它能够比流更好地映射底层操做系统的 API。并发

3. 多路复用器 Selector

多路复用器提供选择已经就绪的任务的能力。Selector 会不断地轮询注册在其上的 Channel,若是某个 Channel 上面发生读或者写事件,这个 Channel 就处于就绪状态,会被 Selector 轮询出来,而后经过 SelectionKey 能够获取就绪 Channel 的集合,进行后续的 I/O 操做。app

2.3.2 NIO 服务端序列图

(1)打开 ServerSocketChannel框架

(2)绑定监听地址 InetSocketAddress

(3)建立 Selector,启动线程

(4)将 ServerSocketChannel 注册到 Selector,监听 ACCEPT

(5)Selector 轮询注册的 Key

(6)handleAccept() 处理新的客户端接入

(7)设置新建客户端链接的 Socket 参数

(8)向 Selector 注册监听读操做 SelectionKey.OP_READ

(9)handleRead() 异步请求消息到 ByteBuffer,收到请求

(10)decode 请求消息

(11)异步写 ByteBuffer 到 SocketChannel,发送响应

2.3.1 NIO 客户端序列图

(1)打开 SocketChannel

(2)设置 SocketChannel 为非阻塞模式,同时设置 TCP 参数

(3)异步链接服务端

(4)判断链接结果,若是链接成功,调到步骤10,不然执行步骤5

(5)向 Reactor 线程的多路复用器注册 OP_CONNECT 事件

(6)建立 Selector,启动线程

(7)Selector 轮询就绪的 Key

(8)handleConnect()

(9)判断链接是否完成,完成执行步骤10

(10)向多路复用器注册读事件 OP_READ

(11)encode 请求消息

(12)异步写 ByteBuffer 到 SocketChannel,发送请求

(13)handleRead() 异步从 SocketChannel 读 ByteBuffer,收到响应

 

2.4 AIO

NIO 2.0 引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步通道提供如下两种方式获取操做结果。

  1. 经过 java.util.concurrent.Future 类表示异步操做的结果;
  2. 在执行异步操做的时候传入一个 java.nio.channels。

CompletionHandler 接口的实现类做为操做完成的回调。

NIO 2.0 的异步套接字通道是真正的异步非阻塞 I/O,对应于 UNIX 网络编程中的事件驱动 I/O(AIO)。它不须要经过多路复用器(Selector)对注册的通道进行轮询操做便可实现异步读写,从而简化了 NIO 的编程模型。

 

2.5 4 种 I/O 的对比

同步阻塞I/O 伪异步I/O 非阻塞I/O(NIO) 异步I/O(AIO)
客户端个数:I/O线程 1:1 M:N M:1 M:0
I/O(阻塞)类型 阻塞 阻塞 非阻塞 非阻塞
I/O(同步)类型 同步 同步 同步(I/O多路复用) 异步
API使用难度 简单 简单 复杂 通常
调试难度 简单 简单 复杂 复杂
可靠性 很是差 很是差
吞吐量

 

2.6 选择 Netty 的理由

什么是 Netty

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

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

Netty 的优势

  • 功能强大
  • 使用简单
  • 性能高
  • 安全
  • 社区活跃
相关文章
相关标签/搜索