当前位置:网站首页>NIO之Selector执行流程
NIO之Selector执行流程
2022-08-02 17:57:00 【i进击的攻城狮】
一、Seletor是什么?
selector 单从字面意思不好理解,Seletor是一个监听器,它可以监听Channel中发生的事件。Channel可以注册在Seletor中,当这些注册的Channel在事件发生时,Seletor的select 方法就会返回这些事件交给 thread 来处理。
二、Seletor和多线程处理的区别
光从上面的解释不好理解,需要结合服务器的设计演化来理解它的用途
多线程版设计
对网络中的客户端socket请求,如果每个请求都开一个线程去处理,那么系统内存占用高,线程上下文切换成本也高,对系统的压力会非常大。
线程池版设计
使用线程池,优化了线程的创建,但是在阻塞模式下,线程仅能处理一个 socket 连接, 仅适合短连接场景
selector版本
selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic)
三、selector单线程处理多socket案例
服务端代码:
@Slf4j
public class ChannelDemo6 {
public static void main(String[] args) {
try (ServerSocketChannel channel = ServerSocketChannel.open()) {
channel.bind(new InetSocketAddress(8080));
System.out.println(channel);
Selector selector = Selector.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int count = selector.select();
log.debug("select count: {}", count);
// 获取所有事件
Set<SelectionKey> keys = selector.selectedKeys();
// 遍历所有事件,逐一处理
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
// 判断事件类型
if (key.isAcceptable()) {
ServerSocketChannel c = (ServerSocketChannel) key.channel();
// 必须处理
SocketChannel sc = c.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
log.debug("连接已建立: {}", sc);
}
else if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(128);
int read = sc.read(buffer);
if(read == -1) {
key.cancel();
sc.close();
} else {
buffer.flip();
debugAll(buffer);
}
}
// 处理完毕,必须将事件移除
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码:
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8080)) {
System.out.println(socket);
socket.getOutputStream().write("world".getBytes());
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
方法解释:
- ServerSocketChannel用来创建服务器的Channel,它有点像ServerSocket.
- channel.configureBlocking(false);设置channel为非阻塞,这样如果accpet的时候,如果没有连接,就会返回null.
- channel.register(selector, SelectionKey.OP_ACCEPT)将channel注册到selector中,监听accept连接事件
- selector.select(),会阻塞,等待客户端连接
- selector.selectedKeys(),事件产生式,会把事件添加到这个集合中
四、selector事件
- accept 产生连接时触发
- connect 客户端建立连接时出发
- read 收到客户端消息时产生可读事件
- 可写事件
边栏推荐
猜你喜欢
redis summary_distributed cache
Security First: Tools You Need to Know to Implement DevSecOps Best Practices
如何构建准实时数仓?
浅谈混迹力扣和codeforces上的几个月
宝塔搭建实测-基于ThinkPHP5.1的wms进销存源码
搭建属于自己的知识库(Wikijs)
攻防世界-favorite_number
Flink Learning 9: Configure the idea to develop the flink-Scala program environment
How to ensure the security of smart factories?
2022安全员-C证考试题库模拟考试平台操作
随机推荐
LeetCode 2343. 裁剪数字后查询第 K 小的数字
Go 语言快速入门指南: 介绍及安装
有关代购系统搭建的那点事
shell中awk命令的if条件语句引入外置变量
9月起中国给予多哥等16国98%税目产品零关税待遇
golang刷leetcode 经典(5)设计哈希集合
Endanger the safety of common Internet attacks have?
2022最新版SSM源码分析:一套教程助你深入理解底层原理,提高核心竞争力!
千万级别的表分页查询非常慢,怎么办?
CUDA+Pycharm-gpu版本+Anaconda安装
mongodb的游标
C#里如何简单的校验时间格式
解决多版本jar包冲突问题
企业云成本管控,你真的做对了吗?
搭建属于自己的知识库(Wikijs)
ffmpeg cannot find libx264 after compilation
攻防世界-favorite_number
How to deal with security risks posed by machine identities
Several common cross-domain solutions
新特性解读 | MySQL 8.0 GIPK 不可见主键