No-Block 和Block IO 的区别:
一个典型的网络通讯步骤为: open (新建socket Chanel )--> connect( 尝试建立连接) --> accept( 连接被接受) --> read( 读取请求)send (输出结果)--> close( 连接关闭) 。
对于一个No-Block 的网络IO ,上面的每一步都是会马上返回的,当然返回的结果可能为null ,可能不为null ,这个要看下上文(context )决定。一般情况下,我们都是需要不为null 的结果,这个就需要我们在适当的时机,执行适当的步骤,这样就会得到我们想要的结果。何为适当的时机?这个下面会讲。
对于一个block 的网络IO ,上面的每一步执行的时候,如果没到适当的时机,当前线程就会被block 住,直到适当的时机,返回给你确定的结果。
当然对与No-Block 或者Block IO ,上面的每一步都有可能会抛出IOException 异常的。
NIO 编程接触的几个关键概念:
Buffer :是一块连续的内存块,是 NIO 数据读或写的中转地。Buffer 这篇blog 暂时略过不讲。
Chanel :数据的源头或者数据的目的地,用于向 buffer 提供数据或者读取 buffer 数据 ,异步 I/O 支持。
注意chanel 有2 类,一种叫SocketChanel, 一种叫ServerSocketChanel ,看名字我们就知道,一类是普通的socket chanel ,client 端和服务器端都用的,一类是专门用在server 端的。当然这个界限也不是绝对的,互为client 和server 的情况也是存在的。
Selector : chanel 事件的侦听者, 它能检测一个或多个通道 (channel) 上的事件,并将事件分发出去。使用一个 select 线程就能监听多个通道上的事件,并基于事件驱动触发相应的响应。
SelectionKey : chanel 上发生的事件, 包含了事件的状态信息和时间以及对应的 chanel 。
Chanel 的状态:
可连( Connectable ):当一个 Chanel 完成 socket 连接操作已完成或者已失败放弃时。
能连( Acceptable ):当一个 Chanel 已经准备好接受一个新的 socket 连接时。
可读( Readable ):当一个 Chanel 能被读时。
可写( Writable ):当一个 Chanel 能被写时。
结合对照上面的网络通讯步骤我们可以有以下推导出的结论:
当一个 Server Chanel 是 Connectable 时, client 端尝试 connect 才会成功。
当一个 Server Chanel 是 Acceptable 时, client 的连接请求被真正受理,一个新的 chanel 会被生成,并且记录了 localAdrress 和 remoteAddress. 为进一步读写做准备。
当一个 Chanel 是 Readable 时,我们从这个 Chanel 中读取数据才会成功。
当一个 Chanel 是 Writable 时,我们往这个 Chanel 中写数据才会成功。
记住一点,对于一个 No-Block 的 Chanel 来说,上面 4 个操作都会马上返回或者抛出 IOException ,但是是不是成功就难说了,前面就说了,我们在一个 Chanel 做操作的时候,我们要密切关注 Chanel 的当前状态。只有在知道 Chanel 的当前状态时,我们才能在这个 Chanel 上做最适当的操作。
聪明的你可能马上就会想到,要是你操作的 Chanel 的状态的转换信息能被你抓取,这些问题就迎刃而解了。对啦, NIO 就是这样设计的。一个 Chanel 可以注册一个 Selector (就像一个事件侦听器),而且你还要告知你想要要侦听的状态。用一段代码来说明下:
- selector = SelectorProvider.provider().openSelector();
- serverChannel1 = ServerSocketChannel.open();
- serverChannel1.configureBlocking(false);
- InetSocketAddress isa = new InetSocketAddress("localhost", 9999);
- serverChannel1.socket().bind(isa);
- serverChannel1.register(selector, SelectionKey.OP_ACCEPT);
这段代码的意思就是我们打开了一个 ServerChanel ,侦听本机的 9999 端口,并且新建了一个 Selector, 然后这个 ServerChanel 注册了这个 Selector ,并且指定了它感兴趣的状态类型是 OP_ACCEPT. 这样有什么效果呢?
注意红色那句,这句意思是selector要求serverChannel1状态为acceptable的时候把这个消息告诉selector。
效果就是:
当这个 ServerChanel 状态为 Acceptable 时, Selector 就会收到一个消息,这个消息当然就是一个 SelectionKey 对象。调用 Selector 的 selectedKeys ()方法,我们就能得到所有 Chanel 发送过来的消息。
因为 SelectionKey 包含 事件的状态,时间以及对应的 Chanel ,很自然的,我们遍历这个 Set<SelectionKey>, 根据 SelectionKey 的状态,就能在相应的 Chanel 做正确的操作。比如,能读的时候我们就读,能写的时候我们就写。
最后讲讲 Server 端和 Client 编程的一般步骤:
对于 Client 来一般是这样的:
- InetSocketAddress isa = new InetSocketAddress(host, port);
- SocketChannel sc = null;
- sc = SocketChannel.open();
- sc.connect(isa);
- sc.write(data);
- …
- Sc.read(buff);
构造一个 InetSocketAddress 对象 --> open --> connect --> write --> read
注意这里用的不是 No-Block 的方式,因为 client 如果没有得到 server 端的正确回应的话就采取下一步操作无疑是没有意义的。
Server 端:
- selector = SelectorProvider.provider ().openSelector();
- serverChannel = ServerSocketChannel.open ();
- serverChannel .configureBlocking( false );
- InetSocketAddress isa = new InetSocketAddress( "localhost" , 9999 );
- serverChannel .socket().bind(isa);
- serverChannel .register( selector , SelectionKey. OP_ACCEPT );
构造一个 Selector --> 打开一个 serverSocketChanel --> 设定 serverSocketChanel 为 no-block-->bind serverSocketChanel 到一个 host 和 port --> register Selector 并告知感兴趣的状态类型转换。
在 SelectionKey Set 上遍历操作:
- while (true) {
- selector.select();
- Iterator selectedKeys = this.selector.selectedKeys().iterator();
- while (selectedKeys.hasNext()) {
- SelectionKey key = (SelectionKey) selectedKeys.next();
- selectedKeys.remove();
- if (!key.isValid()) {
- continue;
- }
- if (key.isAcceptable()) {
- accept(key);
- } else if (key.isReadable()) {
- read(key);
- } else if (key.isWritable()) {
- write(key);
- }
- }
- }
在这个循环里面我们会根据 SelectionKey 的状态,采取不同的操作的。当连接被 accepted 时, 一个新的 chanel 会被生成,并且记录了 localAdrress 和 remoteAddress. 为进一步读写做准备。
accept 函数如下:
- public void accept(SelectionKey key) throws IOException {
- ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
- SocketChanel socketChannel1 = serverSocketChannel.accept();
- socketChannel1.configureBlocking(false);
- socketChannel1.register(selector, SelectionKey.OP_READ);
- }
这里新的 Chanel 被构建,最后同样会注册到 selector , 同时要求当这个 Chanel 为 Readable 时,一个 SelectionKey 被放入到 Selector 中。这样上面循环会用 read(key) 来处理这个 SelectionKey。
原文链接:http://tangay.iteye.com/blog/848485
相关推荐
Java NIO(New IO)是Java 1.4版本引入的一个新模块,它提供了一种不同于传统IO(基于字节流和字符流)的I/O操作方式。传统的IO模型是阻塞式的,而NIO的核心...请务必仔细研究并实践这些示例,以深化你的Java NIO知识。
NIO(New IO)是Java平台中用于处理输入/输出...`nio.zip`这个压缩包包含了有关NIO的CHM文档,对于深入理解和运用Java NIO技术,这是一个非常有价值的资源。建议读者下载并仔细研究,以便更好地利用NIO提升程序性能。
本文探讨了Java NIO(New I/O)框架中的非阻塞通信机制,并对其原理及应用进行了深入研究。NIO是一种现代I/O处理方法,通过引入缓冲区、通道和选择器等新概念,显著提升了文件处理和网络服务器程序的性能。本文首先...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种I/O模型,旨在提供一种更高效、更具...对于任何希望深入理解和使用Java NIO的开发者来说,这些都是不可或缺的知识点。
在“AsynIOModule”这个压缩包中,可能包含了关于Java NIO和AIO编程的相关示例代码和文档,这些资源可以帮助开发者深入理解和实践这两种异步I/O机制,提升他们在Java网络编程中的技能。通过研究这些代码和文档,...
本篇文章将深入探讨这两个概念,并通过示例代码`NonBlockingServer.java`和`Client.java`来展示其工作原理。 首先,Socket是基于TCP/IP协议的应用层接口,它为应用程序提供了一种在网络中发送和接收数据的方式。...
综上所述,“Large-File-Processing-master_javanio_java大文件处理_”项目涵盖了Java NIO在大文件处理中的核心技术和最佳实践,是学习和研究Java高效处理大文件的宝贵资源。通过深入理解这些知识点,并结合项目中的...
Java NIO,全称为New Input/Output,是Java在1.4版本引入的一个新特性,用以替代传统的IO模型。...通过深入研究和分析这个项目,开发者能够更好地掌握NIO在实际项目中的应用,提升系统性能和稳定性。
《Java编程深入研究》涵盖了Java开发的多个重要方面,旨在帮助开发者从基础到高级,全面理解和掌握这门广泛使用的编程语言。在这个过程中,我们将探讨Java的环境配置、服务器的运用,以及一系列实用示例。 首先,...
Java.nio,全称为Java Non-blocking Input/...而压缩包中的"thread"、"noblock"、"block"可能分别对应于线程管理、非阻塞I/O和阻塞I/O的相关示例或讨论,进一步深入研究这些内容,有助于深化对Java.nio的理解和应用。
Java NIO(New IO)是Java 1.4版本引入的一个新特性,全称为Non-blocking Input/Output,即非阻塞I/O。...对于想要深入理解Java NIO或想自己动手搭建服务器的开发者来说,这是一个值得研究的项目。
在JDK 1.6的源码中,你可以深入理解这些概念的实现细节,例如`java.nio`包下的各种类和接口,以及`sun.nio`包中的实现类,这些都是NIO核心功能的实现。`launcher`可能是JVM的启动器,`org`、`javax`、`java`、`com`...
如果你能够获取到这些源代码,那么你将有机会深入研究这个Web服务器的实现细节,了解如何使用Java NIO来处理网络通信,以及它是如何组织和管理请求处理逻辑的。这对于提升你的Java网络编程和服务器开发技能非常有...
### 基于Java NIO开发高性能并发型服务器程序的研究 #### 一、引言 在互联网技术迅速发展的背景下,服务器程序面临着越来越高的并发访问需求。为了满足这一需求,传统阻塞型网络I/O(Input/Output)逐渐暴露出其在...
首先,让我们深入理解Java NIO的核心组件: 1. **通道(Channels)**:通道是数据传输的路径,它可以连接到硬件设备、文件系统或其他的Java NIO组件。Java NIO提供多种类型的通道,如SocketChannel、...
NIO(New Input/Output)是Java平台中用于提高I/O性能的一种编程模型,与传统的BIO(Block I/O)模型相比,NIO提供了非阻塞的读写方式,能够...深入研究NIO的细节,有助于你在开发高效、高并发的服务时做出明智的选择。