Netty快速入门(05)Java NIO 介绍-Selector
Java NIO Selector
Selector是Java NIO中的一个组件,用于检查一个或多个NIO Channel的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。

前面说过通道就是连接,比如同一时间有很多连接过来,这些连接,也就是channel都会注册到Selector中,Selector就会巡视这些channel,看看哪些可以操作(可读或者可写),并不会进行读写操作。而仅仅进行巡视,并不是很麻烦,所以即使Selector是单个线程也是很有效率的,大家不妨想象一下for循环几万次做一些简单的事,比如输出一个字符串,所花费的时间几乎很少就能明白。
Selector之所以叫多路复用,是因为Selector这个线程可以在多个线程之间检查复用,不像bio那样一个线程只负责一个连接。通道连接来了以后要自己注册到Selector中,注册完会返回一个SelectionKey,表示Selector和被注册的channel之间的关系,也是一份凭证。
Selector每次执行select就会返回就绪的通道个数,并更新所有就绪的SelectionKey的状态。下一步就可以迭代所有通道,进行处理了。

服务端代码
上面的理论说完了,下面说一下服务端代码的流程。nio的编程比较复杂和麻烦,所以代码会比bio多很多。首先初始化的时候第一步要创建Selector:
Selector selector = Selector.open();
有了Selector后,服务端要专门创建一个 ServerSocketChannel 去接收客户端的请求连接,这个channel也需要注册到Selector中:
ServerSocketChannel serverChannel = ServerSocketChannel.open(); //创建
serverChannel.configureBlocking(false); //设置为非阻塞
serverChannel.socket().bind(new InetSocketAddress(port), 1024); //绑定端口
serverChannel.register(selector, SelectionKey.OP_ACCEPT); //设置类型为接收连接的线程,并注册到Selector中
上面最后一行的SelectionKey.OP_ACCEPT表示serverChannel只对接收连接有兴趣,其它事不会做,也就是说在把通道注册到Selector中的时候,要告诉Selector通道专门负责做哪一类的事。一个通道可以做的事有四个类型:
SelectionKey.OP_CONNECT //对请求有兴趣
SelectionKey.OP_ACCEPT //对接收有兴趣
SelectionKey.OP_READ //对读操作有兴趣
SelectionKey.OP_WRITE //对写操作有兴趣
初始化服务器的代码如下:

一旦向Selector注册了一个或多个channel后,就可以调用select方法来获取channel,select方法会返回所有处于就绪状态的channel,常用select方法具体如下:
int select()
int select(long timeout)
int selectNow()
select()方法的返回值是一个int,代表有多少channel处于就绪了。也就是自上一次select后有多少channel进入就绪。
在调用select并返回了有channel就绪之后,可以通过选中的key集合来获取channel,这个操作通过调用selectedKeys()方法:
Set selectedKeys = selector.selectedKeys();
接下来看一下获取通道的代码:

上面的逻辑很简单,调用select和selectedKeys获取所有可以操作通道,然后迭代并交给handlerInput方法去处理。这就是selecto获取和r处理所有通道的循环流程。通道分为四种类型,所以通道处理的时候,可以进行四种判断:
while(keyIterator.hasNext()){
SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // 判断通道是不是一个可以接收类型的通道,用在服务端处理的时候做判断 } else if (key.isConnectable()) { // 是否是一个连接类型的通道 } else if (key.isReadable()) { // 通道可读的时候处理 } else if (key.isWritable()) { // 通道可写的时候处理 } keyIterator.remove();
}
上面是根据通道四种类型总共要做的四种判断,最后一行注意,通道处理完后,一定要进行remove,否则还会继续处理。
来看一下接收连接的请求处理:

上面的代码逻辑就是发现一个新请求后,使用SocketChannel接收,然后设置为非阻塞的,最后注册到selector中,设置类型为SelectionKey.OP_READ,最后的sk.attach(num++);表示设置连接的编号。
当连接可读的时候,处理代码如下:

这个代码虽然多,但是逻辑简单,就是读取数据打印到控制台,最后的doWrite方法就是返回信息到客户端:

这里服务端根据实际情况作了两种判断,实际开发中channel存在几种类型就要做几种判断。这里的nio服务端的程序只是一个简单的版本,很多问题比如半包都没有考虑,但是即使这样,也比bio要复杂很多。
客户端代码
客户端代码和服务端流程上差不多,

这里使用的是SocketChannel,注册的时候,客户端要连接服务端,所以类型为SelectionKey.OP_CONNECT,循环获取channel的流程和服务端一样:

看一下处理的方法:

上面判断连接成功后,会发一个消息到服务端,前面看到服务端接收到消息后会自动给客户端返回一个消息,所以客户度也要写一个读的操作:

读的逻辑也是把读到的内容写到控制台。
NIO特性
NIO使用事件驱动模型,以前一个线程只能处理一个连接,现在单个线程可以处理很多channel,相同请求数量的情况下避免线程过多的缺点。NIO是非阻塞IO,IO读写不再阻塞,而是返回0。基于block块的传输,通常比基于流的传输更高效,并且有更高级的IO函数,zero-copy零拷贝等特性,IO多路复用大大提高了java网络应用的可伸缩性和实用性。
NIO只能说在特定的情况下,比如并发量大的时候有优势,但是如果连接数只有几百,并发也不高的情况下,nio并不一定比bio好,速度也不一定比bio快。
NIO屏蔽了底层实现,不同的操作系统多路复用模型也是不同的,比如Linux的epoll,FreeBSD的Kqueue等等,NIO基于各个操作系统的IO系统实现,在不同的平台运行还是有差异存在的,而且编程很困难,容易出各种问题,有很多陷阱,熟练掌握nio需要很多经验和技术功底。
通过上面的总结也说明了我们为什么需要netty这样的框架,会把各种复杂的问题屏蔽掉,让高性能的网络编程变得简单可靠。
代码地址:https://gitee.com/blueses/netty-demo 04
本文由博客一文多发平台 OpenWrite 发布!
Netty快速入门(05)Java NIO 介绍-Selector的更多相关文章
- 【个人笔记】002-PHP基础-01-PHP快速入门-02-PHP语言相关介绍输
002-PHP基础-01-PHP快速入门 02-PHP语言相关介绍 1.PHP是什么 Hypertext Preprocessor超文本预处理器 是一种通用开源脚本语言 Personal Home P ...
- Java NIO类库Selector机制解析(下)
五. 迷惑不解 : 为什么要自己消耗资源? 令人不解的是为什么我们的Java的New I/O要设计成这个样子?如果说老的I/O不能多路复用,如下图所示,要开N多的线程去挨个侦听每一个Channel ...
- Java NIO之Selector(选择器)
历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) Java NIO 之 Channel(通道) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂re ...
- java NIO介绍
前言 我们在写java程序的时候,为了进行优化,把全部的精力用在了处理效率上,但是对IO的关注却很少.这也可能是由以前java早期时JVM在解释字节码时速度慢,运行速率大大低于本地编译代码,因此以前往 ...
- Java NIO类库Selector机制解析(上)
一. 前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...
- Java NIO 选择器(Selector)的内部实现(poll epoll)
http://blog.csdn.net/hsuxu/article/details/9876983 之前强调这么多关于linux内核的poll及epoll,无非是想让大家先有个认识: Java NI ...
- Java NIO类库Selector机制解析--转
一. 前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...
- Java NIO 选择器(Selector)的内部实现(poll epoll)(转)
转自:http://blog.csdn.net/hsuxu/article/details/9876983 之前强调这么多关于linux内核的poll及epoll,无非是想让大家先有个认识: Java ...
- Netty快速入门(03)Java NIO 介绍-Buffer
NIO 介绍 NIO,可以说是New IO,也可以说是non-blocking IO,具体怎么解释都可以. NIO 1是在JSR51里面定义的,在JDK1.4中引入,因为BolckingIO不支持高并 ...
随机推荐
- 洛谷P4018 Roy&October之取石子 题解 博弈论
题目链接:https://www.luogu.org/problem/P4018 首先碰到这道题目还是没有思路,于是寻思还是枚举找一找规律. 然后写了一下代码: #include <bits/s ...
- Error: Cannot find module 'webpack/bin/config-yargs' 报错原因, webpack@4.X踩的坑~
1 .使用webpack@4.32.2时, 当我通过package.json的script去执行webpack-dev-server时, 报以下错误: Error: Cannot find modu ...
- npx cowsay 让动物说话~
发现个好玩的东东, 忍不住想分享出来, 好可爱, 哈哈哈~~ node环境执行命令: npm i cowsay -D npx cowsay hello! npx cowsay -f sh ...
- [C++] 自动关闭右下角弹窗
最近腾讯.迅雷等各种客户端,都越发喜欢在屏幕的右下角弹框了. 有骨气的人当然可以把这些软件卸载了事,但是这些客户端在某些情况下却又还是有用的.怎么办呢? 作为码农,自己实现一个自动关闭右下角弹窗的程序 ...
- python模块之模块导入
模块的导入 """ 模块的导入使用:模块导入一般都要放在代码的最上面 不同模块的导入顺序: 1 内置模块 2 扩展模块 3 自定义模块 """ ...
- angular 点击事件阻止冒泡及默认行为
经常遇到场景:多层级元素绑定ng-click 事件,则底层元素的点击事件存在冒泡现象,怎么解决? 类似原生JS ,只是语法稍有不同,如下: 阻止冒泡 $event.stopPropagation() ...
- HDU 3974 Assign the task
Assign the task Problem Description There is a company that has N employees(numbered from 1 to N),ev ...
- webpack打包前删除之前的所有文件
安装插件: npm install --save-dev clean-webpack-plugin 在webpack.prod.conf.js 中引入: const { CleanWebpackPl ...
- 快排java代码
定一个基准位,递归左右两边排序. public void fun(){ int arr[] = {2,3,4,5,6,7,822,3,4,5,8,6,5,4,2,1}; //System.out.pr ...
- UI 素材相关收集
图标素材收藏网址 阿里:iconfont.cn 图片压缩:https://tinypng.com/ gif动图压缩:https://tool.gifhome.com