NIO相关概念之Selector
选择器(selector):
选择器管理者一个被注册的通道的集合信息和它们的就绪状态.通道是和选择器一起被注册的,并且使用选择器来更新通道的就绪状态,当这么做的时候,可以选择被激发的线程挂起,直到有就绪的通道
可选择通道(SelectableChannel)
这个抽象类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的通道类的父类。FileChannel对象不是可选择的,因为它们没有继承SelectableChannel。所有socket通道都是可选择的,包括从管道(Pipe)对象的中获得的通道。SelectableChannel可以被注册到Selector对象上,同时可以指定对那个选择器而言,那种操作是感兴趣的。一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。
选择键(SelectionKey)
选择键封装了特定的通道与特定的选择器的注册关系。选择键对象被SelectableChannel.register( ) 返回并提供一个表示这种注册关系的标记。选择键包含了两个比特集(以整数的形式进行编码),指示了该注册关系所关心的通道操作,以及通道已经准备好的操作。
就绪选择的相关类之间的关系如下:

调用可选择通道的register( )方法会将它注册到一个选择器上。如果您试图注册一个处于阻塞状态的通道,register( )将抛出未检查的IllegalBlockingModeException异常。
此外,通道一旦被注册,就不能回到阻塞状态。试图这么做的话,将在调用configureBlocking( )方法时将抛出IllegalBlockingModeException异常。并且,理所当然地,试图注册一个已经关闭的SelectableChannel实例的话,也将抛出ClosedChannelException异常,就像方法原型指示的那样
尽管SelectableChannel类上定义了register( )方法,还是应该将通道注册到选择器上,而不是另一种方式。选择器维护了一个需要监控的通道的集合。一个给定的通道可以被注册到多于一个的选择器上,而且不需要知道它被注册了那个Selector对象上。将register( )放在SelectableChannel上而不是Selector上,这种做法看起来有点随意。它将返回一个封装了两个对象的关系的选择键对象。重要的是要记住选择器对象控制了被注册到它之上的通道的选择过程。
选择器才是提供管理功能的对象,而不是可选择通道对象。选择器对象对注册到它之上的通道执行就绪选择,并管理选择键。
对于键的interest(感兴趣的操作)集合和ready(已经准备好的操作)集合的解释是和特定的通道相关的。每个通道的实现,将定义它自己的选择键类。在register( )方法中构造它并将它传递给所提供的选择器对象。
以下是一个基于selector来实现的一个Http服务器端:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
/**
* Created with Intellij IDEA
*
* @author: jiaoyiping
* Mail: jiaoyiping@gmail.com
* Date: 2018/07/22
* Time: 11:18
* To change this template use File | Settings | Editor | File and Code Templates
*/
public class HttpServer {
private static final Logger logger = LoggerFactory.getLogger(HttpServer.class);
private static final int DEFAULT_TIME_OUT = 3000;
private static final int DEFAULT_HTTP_PORT = 8080;
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(DEFAULT_HTTP_PORT));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select(DEFAULT_TIME_OUT) == 0) {
logger.info("没有接收到客户端的请求,继续等待");
continue;
}
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
Handler handler = new Handler();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
handler.handleAccept(key);
}
if (key.isReadable()) {
handler.handleRead(key);
}
keyIterator.remove();
}
}
}
private static class Handler {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private static final String DEFAULT_HTTP_RESPONSE_HEADER = "HTTP/1.1 200 OK\nContent-Type: text/html;charset=UTF-8\n\r\n";
private static final String DEFAULT_CHAR_SET = "UTF-8";
public void handleAccept(SelectionKey key) throws IOException {
SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
socketChannel.configureBlocking(false);
socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(DEFAULT_BUFFER_SIZE));
}
public void handleRead(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
buffer.clear();
if (socketChannel.read(buffer) == -1) {
logger.debug("没有从请求中读取到内容");
socketChannel.close();
return;
}
buffer.flip();
String receivedString = Charset.forName(DEFAULT_CHAR_SET).newDecoder().decode(buffer).toString();
logger.info("收到了客户端的请求:\n{}", receivedString);
//返回数据给客户端
String message = "<html><body>黄河远上白云间</body></html>";
ByteBuffer sendData = ByteBuffer.wrap((DEFAULT_HTTP_RESPONSE_HEADER + message).getBytes());
socketChannel.write(sendData);
socketChannel.close();
}
}
}
NIO相关概念之Selector的更多相关文章
- epoll浅析以及nio中的Selector
出处: https://my.oschina.net/hosee/blog/730598 首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference) ...
- epoll 浅析以及 nio 中的 Selector
首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference): 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作 ...
- 两种 NIO 实现:Selector 与 Epoll
[总结]两种 NIO 实现:Selector 与 Epoll 时间2012-11-17 08:38:42 开源中国新闻原文 http://my.oschina.net/ielts0909/blog/ ...
- Java I/O(4):AIO和NIO中的Selector
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在Java NIO的三大核心中,除了Channel和Buffer,剩下的就是Selector了.有的地方叫它选择器,也有叫多路复用器的(比如Ne ...
- 【总结】两种 NIO 实现:Selector 与 Epoll
时间2012-11-17 08:38:42 开源中国新闻原文 http://my.oschina.net/ielts0909/blog/89849 我想用这个话题小结下最近这一阶段的各种测试和开发. ...
- 7. 彤哥说netty系列之Java NIO核心组件之Selector
--日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇. 简介 上一章我们一起学习了Java NIO的核心组件Buffer,它通常跟Channel一起使用,但是它们在网络IO中又该如何 ...
- 3、nio中的selector使用
通过编写一个客户端和服务器端的例子来熟悉selector的使用 服务端逻辑: 1. 绑定一个端口号2. channel注册到selector中3. 用死循环来监听如果有时间发生,遍历selection ...
- NIO(三):Selector选择器
一.堵塞式与非堵塞式 在传统IO中,将数据由当前线程从客户端传入服务端,由服务端的内核进行判断传过来的数据是否合法,内核中是否存在数据. 如果不存在数据 ,并且数据并不合法,当前线程将会堵塞等待.当前 ...
- Java NIO之选择器Selector
在单独的线程中,检查多个通道是否可以进行IO操作. Selector创建:静态工厂方法创建 Selector selector = Selector.open(); 注册通道 channel.conf ...
随机推荐
- StackExchange.Redis 管道 批量 高性能插入数据
现在用redis来做数据缓存的越来越多了,很多项目都有初始化redis数据的过程,由于初始化的数据比较大,那么该过程越快越好.这里我们以HashSet方法为例, 这里我们推荐用HashEntry[] ...
- .NET 11 个 Visual Studio 代码性能分析工具
原文地址 软件开发中的性能优化对程序员来说是一个非常重要的问题.一个小问题可能成为一个大的系统的瓶颈.但是对于程序员来说,通过自身去优化代码是十分困难的.幸运的是,有一些非常棒的工具可以帮助程序员进行 ...
- 微软BI 之SSIS 系列 - 变量查询语句引起列输出顺序不一致的解决方法
开篇介绍 这个问题来自于 天善BI社区,看了一下比较有意思,因为我自己认为在 SSIS中处理各种类型文件的经验还比较丰富(有一年的时间几乎所有ETL都跟文件相关),但是这个问题确实之前没有特别考虑过. ...
- linux 删除换行符
今天需要删除文件里面的换行符,比如有一个文件a.txt: 1,2,3 4,5,6 1,2,3 4,5,6 1,2,3 4,5,6 1,2,3 4,5,6 1,2,3 4,5,6 1.使用vim删除换行 ...
- Mysql INSERT、REPLACE、UPDATE的区别
用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句.言外之意,就是对数据进行修改.在标准的SQL中有3个语句,它们是INSE ...
- 【C语言】符号优先级
一. 问题的引出 今天看阿里的笔试题,看到一个非常有意思的题目,但是很容易出错. 题目:如下函数,在32bit系统foo(2^31-3)的值是: Int foo(int x) { return x&a ...
- 把linux的man手册转化为windows下可读的格式
原文链接: http://www.linux521.com/2009/system/200904/1542.html 把linux的man手册转化为windows下可读的格式 我也是一个Linux学习 ...
- 菜鸟要做架构师(二)——java性能优化之for循环
完成同样的功能,用不同的代码来实现,性能上可能会有比较大的差别,所以对于一些性能敏感的模块来说,对代码进行一定的优化还是很有必要的.今天就来说一下java代码优化的事情,今天主要聊一下对于for(wh ...
- 从一道面试题来认识java类加载时机与过程【转】
说明:本文的内容是看了<深入理解Java虚拟机:JVM高级特性与最佳实践>后为加印象和理解,便记录了重要的内容. 1 开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可 ...
- js实现禁止pc端浏览器缩放和获取当前页面浏览器的缩放大小
众所周知:移动端页面禁止用户缩放界面只需加上<meta name="viewport" content="user-scalable=0">即可,但 ...