NIO核心三:Selector

一、基本概念

选择器提供一种选择执行已经就绪的任务的能力。selector选择器可以让单线程处理多个通道。如果程序打开了多个连接通道,每个连接的流量都比较低,可以使用Selector对通道进行管理。
在这里插入图片描述

二、如何创建选择器

1.创建Selector

Selector selector = Selector.open();

2.必须将通道设置为非阻塞模式才能注册到选择器上

Channel.configureBlocking(false);

3.把通道注册到选择器上,会返回一个选择键

SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);

SelectionKey的操作有:

  • SelectionKey.OP_CONNECT,指某个通道连接到服务器
  • SelectionKey.OP_ACCEPT,只有ServerSocketChannel有这个事件,查看是否有新的连接
  • SelectionKey.OP_READ,是否有可读的通道就绪
  • SelectionKey.OP_WRITE,写数据的通道是否就绪

注册完成后,可以调用select()方法轮询是否有就绪的通道

int count = selector.select();

select()方法,返回就绪的通道数量

三、服务器端模板

//服务器端模板代码
public static void Server_Standard_Code_template() {try {ServerSocketChannel ssc=ServerSocketChannel.open();ssc.socket().bind(new InetSocketAddress("localhost",80));//只有设置为非阻塞才能注册到选择器中ssc.configureBlocking(false);//创建一个选择器Selector selector = Selector.open();//通道注册进选择器中---监听客户端连接事件ssc.register(selector, SelectionKey.OP_ACCEPT);while(true){//获取以及就绪的通道数量int select = selector.select();//没有通道就绪if(select==0){continue;}//获取已经就绪的Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()){SelectionKey selectionKey = iterator.next();//客户端连接请求事件if(selectionKey.isAcceptable()){//接收连接}else if(selectionKey.isReadable()){//读取数据}else if(selectionKey.isWritable()){//写数据}//移除iterator.remove();}}} catch (IOException e) {e.printStackTrace();}
}

四、NIO通讯实例

服务器端

public class NIOServer {//通道管理器private Selector selector;/*** 获取一个ServerSocket通道,并对该通道做一些初始化工作* @param port 端口号* @throws IOException*/public void initServer(int port) throws IOException {//获取一个ServerSocket通道ServerSocketChannel socketChannel = ServerSocketChannel.open();//设置通道为非阻塞socketChannel.configureBlocking(false);//将通道对应的ServerSocket绑定到port端口socketChannel.socket().bind(new InetSocketAddress(port));//获取一个通道管理器this.selector = Selector.open();/*** 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件* 注册该事件后,当该事件到达时,selector.select()会返回* 如果该事件没有到达,selector.select()会一直阻塞*/socketChannel.register(selector, SelectionKey.OP_ACCEPT);}public void listen() throws IOException {while (true){//当注册的事件到达时,方法返回,否则该方法一直阻塞selector.select();//获取selector中选项的迭代器Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();while (iterator.hasNext()){SelectionKey key = iterator.next();//删除已经选择的key,防止重复处理iterator.remove();//客户端连接请求事件if(key.isAcceptable()){//接收连接ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();//获取客户端连接的通道SocketChannel channel = serverSocketChannel.accept();//设置为非阻塞channel.configureBlocking(false);//向客户端发送数据源ByteBuffer buf = ByteBuffer.allocate(1024);String message = "你好我是服务器端,我接收到了你的消息";buf.put(message.getBytes(StandardCharsets.UTF_8));//把缓冲区切换成读取模式buf.flip();//将buffer写入channelwhile (buf.hasRemaining()){channel.write(buf);}//和客户端连接成功后,为了接收到客户端的信息,需要给通道设置读取权限channel.register(this.selector,SelectionKey.OP_READ);}else if(key.isReadable()){//读取数据read(key);}}}}public void read(SelectionKey key) throws IOException {//得到事件发生的socket通道SocketChannel channel = (SocketChannel) key.channel();//创建读取的缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);//将数据读取到缓冲区channel.read(buffer);// 4、把缓冲区切换成写出模式buffer.flip();String rs = new String(buffer.array(),0,buffer.remaining());System.out.println(rs);}public static void main(String[] args) throws IOException {NIOServer server = new NIOServer();server.initServer(8100);server.listen();}
}

客户端

public class NIOClient {//通道管理器private Selector selector;public static void main(String[] args) throws IOException {NIOClient client = new NIOClient();client.initClick("127.0.0.1",8100);client.listen();}public void initClick(String ip,int port) throws IOException {//获取一个socketSocketChannel channel = SocketChannel.open();//设置通道为非阻塞channel.configureBlocking(false);//获取一个通道管理器this.selector = Selector.open();channel.connect(new InetSocketAddress(ip,port));channel.register(this.selector, SelectionKey.OP_CONNECT);}public void listen() throws IOException {while (true){selector.select();Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();while (iterator.hasNext()){SelectionKey key = iterator.next();iterator.remove();if(key.isConnectable()){SocketChannel channel = (SocketChannel) key.channel();if(channel.isConnectionPending()){channel.finishConnect();}//设置为阻塞channel.configureBlocking(false);//向客户端发送数据源ByteBuffer buffer = ByteBuffer.allocate(1024);String  message = "服务器端你好,我是客户端";buffer.put(message.getBytes(StandardCharsets.UTF_8));//把缓冲区切换成读取模式buffer.flip();//将buffer写入channelwhile (buffer.hasRemaining()){channel.write(buffer);}channel.register(this.selector,SelectionKey.OP_READ);}else if(key.isReadable()){read(key);}}}}public void read(SelectionKey key) throws IOException {SocketChannel channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);channel.read(buffer);byte[] data = buffer.array();// 4、把缓冲区切换成写出模式buffer.flip();String rs = new String(data,0,buffer.remaining());System.out.println(rs);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/508181.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

类加载器分类

类加载器&#xff08;Class Loader&#xff09;是Java虚拟机&#xff08;JVM&#xff09;的一个重要组件&#xff0c;负责加载Java类到内存中并使其可以被JVM执行。类加载器是Java程序的核心机制之一。 主要有一下四种类加载器&#xff1a; &#xff08;1&#xff09;启动类加…

Bootstrap的使用

目录 js的引入&#xff1a; 1.行内式 2.嵌入式 3.外链式 Bootstrap:的引入 注意事项&#xff1a; 条件注释语句&#xff1a; 栅格系统&#xff1a; 列嵌套&#xff1a; 列偏移&#xff1a; 列排序&#xff1a; 响应式工具&#xff1a; Bootstrap的字体图标的使用&a…

内含资料下载丨黄东旭:2024 现代应用开发关键趋势——降低成本、简化架构

作为一名工程师和创业者&#xff0c;创办 PingCAP 是我进入创新世界的一次深潜。这段旅程既有令人振奋的发现&#xff0c;也充满令人生畏的不确定性。作为这次探险之旅见证的 TiDB &#xff0c;现在已在全球服务超过 3000 家企业&#xff0c;其中有已经实现了商业成功的大公司&…

【STM32+HAL】姿态传感器陀螺仪MPU6050模块

一、准备工作 有关OLED屏初始化的问题&#xff0c;详见【STM32HAL】OLED显示初始化配置 二、所用工具 1、芯片&#xff1a;STM32F10C8T6 2、CUBEMX配置软件 3、 6 轴运动处理组件MPU6050 三、实现功能 OLED屏显示姿态角 四、HAL配置步骤 1、开启I2C1进行MPU6050通信 2、开…

UniApp项目处理小程序分包

目前 uniApp也成为一种 App端开发的大趋势 因为在目前跨端 uniApp可以说相当优秀 可以同时兼容 H5 PC 小程序 APP 的技术 目前市场屈指可数 那么 说到微信小程序 自然就要处理分包 因为微信小程序对应用大小限制非常铭感 限制在2MB 超过之后就会无法真机调试与打包 不过需要注…

3. springboot中集成部署vue3

1. vue3构建 构建命令 npm run build&#xff0c; 构建的结果在disc目录&#xff1a; 2. springboot集成 2.1 拷贝vue3构建结果到springboot resources/static目录 2.2 springboot pom依赖 添加thymeleaf依赖 <dependency><groupId>org.springframework.boot</…

34 Elasticsearch入门

Elasticsearch入门 Elasticsearch简介 一个分布式的、Restful风格的搜索引擎。 分布式&#xff1a;多台服务器集群部署 Restful风格&#xff1a;设计风格&#xff0c;规定了不同种类请求格式&#xff0c;是对请求的标准的一种描述 支持对各种类型的数据的检索。结构化 非结构…

【学习心得】AES对称加密入门

AES&#xff0c;全称Advanced Encryption Standard&#xff08;高级加密标准&#xff09;&#xff0c;是一种广泛采用的对称密钥分组密码算法。 一、对称加密&#xff08;Symmetric Cryptography&#xff09; &#xff08;1&#xff09;定义 对称加密使用相同的密钥来加密和解…

在ubuntu上安装hadoop完分布式

准备工作 Xshell安装包 Xftp7安装包 虚拟机安装包 Ubuntu镜像源文件 Hadoop包 Java包 一、安装虚拟机 创建ubuntu系统 完成之后会弹出一个新的窗口 跑完之后会重启一下 按住首先用ctrlaltf3进入命令界面&#xff0c;输入root&#xff0c;密码登录管理员账号 按Esc 然后输入 …

代码随想录第45天|● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

文章目录 ● 198.打家劫舍思路代码1.dp数组两个变量 ● 213.打家劫舍II思路&#xff1a;代码 ● 337.打家劫舍III思路代码&#xff1a; ● 198.打家劫舍 思路 代码 1.dp数组 class Solution {public int rob(int[] nums) {if(nums.length1)return nums[0];int[] dpnew int[nu…

达梦运维工具-DEM搭建

运维监控工具-DEM 前言 根据达梦官网文档整理 一、工具介绍 DM企业管理器&#xff08;DM Enterprise Manager&#xff0c;简称为DEM&#xff09;提供一个通过Web 界面来监控、管理并维护DM数据库的集中式管理平台。数据库管理员可通过任意Web应用登录DEM&#xff0c;从而对…

Android 多桌面图标启动, 爬坑点击打开不同页面

备注 &#xff1a; MainActivity 正常带界面的UI MainActivityBt 和 MainActivityUsb 是透明的&#xff0c;即 android:theme"style/TranslucentTheme" ###场景1:只有MainActivity 设置成&#xff1a;android:launchMode"singleTask" 点击顺序&#xff1…