一.题记
可能你会问,为什么选择selector作为NIO的开场白,这是因为我在了解到NIO技术之后,觉得selector机制是NIO技术的核心,可以说如果真的理解了selector也就差不多理解了NIO ;
二.引子
NIO是Java网络编程的重要组成部分,在JDK1.4之前由于SUN对于NIO机制缺失,导致Java在编写服务器端多路复用程序时显得能力捉急,下图所示的是在没有NIO时,多路复用程序的写法 :
上图我们可以这样去理解,客户端和服务端通信需要建立信道,而后信道开始传输数据,可是服务端如何知道信道是否有数据来了呢?
这就需要在服务端起一个线程负责监听这一信道,一般认为这一线程都会执行一个死循环程序,时刻盯着信道看是否有数据读写,这样以来,每建立一个信道就要在服务端起一个线程负责监听。
三.存在的问题
1:很多的应用程序都需要极多的信道保持通信(这些信道并不是随时都有数据写入,很大情况下是处于空闲状态的),这种情况下不可能同时创建这么多线程来保持连接(可能多达上百万个)。
2:即使假设拥有一台性能无敌的服务器,以至于可以不考虑线程数量,由于Java线程的机制也很难通过设计线程的优先级以使得某些客户端拥有更高的优先级(经常会有这样的需求,要求给某些信道更高的优先级)。
3:另一个问题则更为现实,CPU的资源是有限和宝贵的,当服务器存在着大量的线程时,由于必然的CPU上下文切换,导致CPU资源消耗严重,同时由于多线程要求编写线程同步程序,其难度远远高于单线程。
于是 .......
革命之后(不能算是革命吧,改良更合适,博主的配图激进了)诞生了NIO及NIO的selector机制 .... 请看以下配图(这里忽略了NIO的其它技术,比如channel、buffer,这些会在之后的文章中专门讲到,这不涉及代码,只要能够根据配图理解原理就好)
先看一个比方,看过英剧《唐顿庄园》么?在没有电话的时代,豪门庄园里,老爷、太太、少爷、小姐、七大姑八大姨 .... ,各自的房间都有一个拉绳,这绳子穿过房间,像电话线一样在房屋中走线,最后所有的线都汇总抵达管家的办公室,线末端系着一个铃铛,只要房子里的人一拉绳子,管家就会知道需要进行某种工作了。铃铛可能有不同的颜色,代表着不同的含义 .....
上面的这个通俗的例子大致描述了selector机制,客户端和服务端以channel的形式建立信道,在服务端取得一selector的实例,很多的channel注册到selector中,就像管家注视着所有房间的拉绳,selector也监视着这些channel是否有数据流动,如果发生数据流动,会根据数据流动的类型(是读数据?写数据?还是请求链接?接受链接?)做出相应的处理(所谓的处理,也就是你需要具体编写的业务逻辑了)。上图中的channel有的是实心的、空心的、间断的、波形的,这代表着不同的数据流动,这是一种博主的比如,各位不要误会 ...
写在这里如果能够理解以上对NIO_selector大话般描述,就可以了,先不要涉及具体的代码,你需要记住的是这些:
1:一个selector负责监听多个信道 ;
2:selector负责两件事,并且这两件事的处理是有顺序的,第一监视各个channel是否有数据变动,第二判断这些数据变动是哪一种类型(是读数据?写数据?还是请求链接?接受链接?) ;
3:selector背后只有一个线程(这里一定要记住是单线程)处理这一切(挨个的处理每一个channel的数据变动)
(博主这里是有的用词“数据变动”是一种形象的描述,就是说有事儿要处理了,博主对于官方中出现的“channel准备就绪”这一描述感觉不太容易理解,所以没有使用)
如果你读懂了以上对于NIO_selector机制的描述,大概也能想到要写一个NIO的server程序应该必备的逻辑
四.需求分析
1:需要在客户端和服务端建立起相应的通信信道 ;
2:开启一个selector实例 ;
3:将相应的信道和selector进行绑定,selector开始负责监视 ;
4:selector进行设置,要使得selector知道对于哪些信道当发生哪些数据变动时应该进行怎样的处理 ;
5:信道需要绑定到相应的地址 ;
6:存在一个死循环,不间断的进行监听、判定、处理 ;
下面我们开始通过一些具体的代码来进行分析 ,首先给出客户端的代码:
public class NioSelectorClient {
public static void main(String[] args) throws IOException {
// 开启channel
SocketChannel channel = SocketChannel.open() ;
// 将channel设置为非阻塞模式(这个后面会解释,这里先记住selector机制一定是非阻塞模式
channel.configureBlocking(false) ;
// 设置channel连接的地址和端口
channel.connect(new InetSocketAddress("127.0.0.1", 8000)) ;
}
}
再来看服务器端的代码:
public class NioSelectorServer {
public static void main(String[] args) throws IOException {
// 开启一个selector选择器(这个是少不了的)
Selector selector = Selector.open() ;
// 开启一个通道 (这个也应该没什么问题)
ServerSocketChannel channel = ServerSocketChannel.open() ;
// 绑定到9000端口(可见这以上几行代码都很常规,也很好理解)
channel.socket().bind(new InetSocketAddress(8000)) ;
// 将channel设置为non-blocking(非阻塞)模式,这个之后要讲,先记住即可
channel.configureBlocking(false) ;
/**
* (这一步很重要)首先将selector和channel进行关联,
* 其次还要让selector明白,判断一个信道的哪一种“数据变动”发生时,应该进行怎样的处理,
* 这就需要将称之为“我们感兴趣的数据变动”(官方称之为“interest set”)和相应的信道关联起来。
*
* 注意这里的channel调用register方法是有返回值的,这个后面会讲到。
* OP_ACCEPT表示我们将选择的“接受事件(OP_ACCEPT)”作为我们“感兴趣的事 件”和相应的channel(也就是前面开启的channel)
* 进行了关联 ;
*/
channel.register(selector, SelectionKey.OP_ACCEPT) ;
// 必然出现的“死循环”,使得服务端始终处于监听状态
while(true) {
/**
* 这是最关键的一步,我称之为“信道状态检查”,
* 官方的API是这样描述的:
* Selects a set of keys whose corresponding channels
* are ready for I/O operations
* 这个后面会详细讲到,这里理解为“信道状态检查”即可
*/
selector.select() ;
/**
* 以下的代码我先不做说明,这里只需要理解以下代码使得程序在得知哪些信道需要进行处理后,
* 进行了相应业务逻辑的处理,由于信道不止一个,所以必然出现遍历操作 ;
*/
for(Iterator<SelectionKey> iterator = selector.selectedKeys().
iterator(); iterator.hasNext();) {
SelectionKey key = iterator.next() ;
iterator.remove() ;// 这步不能少
System.out.println(key.readyOps()) ;
if(key.isAcceptable()) {
System.out.println("Accept") ;
//以下代码就可以开始你的业务逻辑了
channel.accept() ;
} else if(key.isConnectable()) {
} else if(key.isReadable()) {
} else if(key.isWritable()) {
}
}
}
}
}
先写到这里,之后的文章将会具体分析代码的细节,同时对常用的selectorAPI进行解释 ;
未完待续....
相关推荐
Java_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.doc
下面我们将详细探讨Java NIO中的Selector机制。 1. **Selector的作用** Selector的主要功能是监控多个通道的状态变化,例如连接建立、数据到达或者关闭等事件。通过注册感兴趣的事件类型到Selector,程序可以在一个...
标题“nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio”表明这个压缩包包含了一个关于Java NIO的实例,特别是关于NIO套接字(Socket)的编程示例。NIO套接字是Java NIO库中用于网络通信的关键组件,它们允许...
标题中提到的"java_Nio_server_and_j2me_client.rar"是一个包含Java NIO服务器和J2ME客户端的应用示例。J2ME(Java Micro Edition)是Java平台的一个子集,主要用于移动设备和嵌入式设备。在这个项目中,NIO服务器...
NIO在Java 1.4版本中引入,其核心是Channel、Buffer和Selector三大组件。下面将详细介绍这三个主要概念以及NIO在实际开发中的应用。 1. **Channel(通道)**:Channel类似于传统I/O中的流,但有显著的不同。在NIO中...
标题中的“nioserver.zip_NIO_event driven java_java nio_java nioserv_nioser”表明这是一个关于Java NIO的服务器实现,且是基于事件驱动模式的。事件驱动编程是一种设计模式,它允许程序对特定事件做出响应,而...
NIO的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。在给定的压缩包文件中,我们关注的是"FastCopyFile.java"、"UseFloatBuffer.java"以及NIO中的文件锁功能。 首先,让我们详细了解一下`...
`java_nio_chm`指的是包含Java NIO相关内容的CHM(Compiled Help Manual)文件,这是一种Windows下的帮助文档格式,通常包含一系列的章节和索引,方便用户查阅。在这个文档中,你可以找到关于Java NIO类库的详细说明...
尚硅谷__NIO__源码、课件 ·01. 尚硅谷_NIO_NIO 与 IO 区别 ·02. 尚硅谷_NIO_缓冲区(Buffer)的数据存取 ·03. 尚硅谷_NIO_直接缓冲区与非直接缓冲区 ·04. 尚硅谷_NIO_通道(Channel)的原理与获取 ·05. 尚硅谷_...
资源名称:Java_NIO框架Netty教程资源截图: 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
学习Java_NIO 很 不 错 的 材 料, 很 值 得 大 家 学 习。
在标题中提到的“java-nio.rar_java nio_nio 对象实例化”,我们可以理解为这个压缩包中包含了关于Java NIO对象实例化的具体示例或教程。下面我们将详细讨论NIO中的核心对象及其实例化方法。 1. **通道(Channel)*...
### JAVA_NIO学习总结 #### 重要知识点概览 JAVA_NIO(Non-blocking I/O,非阻塞I/O)是Java平台中用于替代传统IO(Blocking IO)的一种高性能IO处理模型,首次出现在JDK 1.4中。NIO通过引入通道(Channel)和缓冲区...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代标准I/O(BIO)模型的新选择。NIO在Java 1.4版本中引入,旨在提高I/O操作的效率,特别是在处理大量并发连接时,如服务器...
本文将深入探讨Java NIO中的Selector机制,并通过源码分析来理解其实现原理。 Selector机制是Java NIO中的核心组件,它允许单线程同时监控多个通道(Channels)的状态变化,例如连接就绪、数据可读或可写等。这种...
在本项目"chacha.rar_NIO soclet java_java nio"中,开发者使用Java NIO实现了一个用户动态口令的认证系统,并结合了MongoDB数据库来存储和管理数据。 1. **Java NIO基础**: - **通道(Channels)**:NIO的核心...
- Java NIO的Selector通过轮询检查多个通道的就绪状态,避免了传统I/O中必须为每个连接创建单独线程的开销。 3. **异步连接池** - **连接池**:在高并发环境下,为了减少建立和销毁网络连接的开销,通常会使用...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一个新特性,旨在提供一种更高效、更具选择性的I/O操作方式。相较于传统的IO模型,NIO的核心优势在于其非阻塞特性,允许...
NIO通过引入Buffer、Channel和Selector等关键组件,为Java开发者提供了一种高效且灵活的I/O操作机制。通过对NIO API的深入了解和应用,可以在各种高性能应用中显著提高系统的吞吐量和响应速度。随着技术的发展,NIO...