3、nio中的selector使用
通过编写一个客户端和服务器端的例子来熟悉selector的使用
服务端逻辑:
1. 绑定一个端口号
2. channel注册到selector中
3. 用死循环来监听如果有时间发生,遍历selectionKey set
4. 判断发生的事件类型,前面会注册accept事件,如果发生accept事件,那么注册读事件,同时清除selectionKey set 中的当前元素。、
5. 接收事件时,将channel保存下来。
6. 发生读事件时,说明有信息,发过来了,那么将消息,转发给所有的客户端。然后清除自身的事件。
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.net.ServerSocket;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.ServerSocketChannel;
- import java.nio.channels.SocketChannel;
- import java.nio.charset.Charset;
- import java.util.*;
- public class NioServer {
- private static HashMap<String, SocketChannel> clientMap = new HashMap<String, SocketChannel>();
- public static void main(String[] args) throws IOException {
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- ServerSocket serverSocket = serverSocketChannel.socket();
- serverSocket.bind(new InetSocketAddress(8899));
- Selector selector = Selector.open();
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- while(true) {
- int number = selector.select();
- // System.out.println("number:" + number);
- Set<SelectionKey> selectionKeySet = selector.selectedKeys();
- Iterator<SelectionKey> iterable = selectionKeySet.iterator();
- if(number > 0 ) {
- while(iterable.hasNext()) {
- SelectionKey selectionKey = iterable.next();
- if(selectionKey.isAcceptable()) {//如果是可接收连接的
- ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
- SocketChannel socketChannel = ssc.accept();
- socketChannel.configureBlocking(false);
- socketChannel.register(selector, SelectionKey.OP_READ);//注册读事件
- clientMap.put(UUID.randomUUID() + "", socketChannel);//保存下channel
- iterable.remove();
- } else if(selectionKey.isReadable()){//可读的
- SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
- ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
- int readCount = socketChannel.read(byteBuffer);
- //这里本该用while
- if(readCount > 0 ) {//读取到数据,就写回到其他客户端
- byteBuffer.flip();
- Charset charset = Charset.forName("UTF-8");
- String receiveStr = new String(charset.decode(byteBuffer).array());
- System.out.println(socketChannel + " receive msg :" + receiveStr);
- String sendKey = "";
- for(Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {//第一遍遍历找到发送者
- if(socketChannel == entry.getValue()) {
- sendKey = entry.getKey();
- break;
- }
- }
- for (Map.Entry<String, SocketChannel> entry: clientMap.entrySet() ) {//给每个保存的连接,都发送消息
- ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
- writeBuffer.put((sendKey + ":" + receiveStr).getBytes());
- writeBuffer.flip();
- entry.getValue().write(writeBuffer);
- }
- }
- iterable.remove();//这个 删除很关键 每次循环完selectionKeySet ,一定要清楚事件,不然肯定会影响下一次的事件触发,或者直接不触发下次的事件
- }
- }
- }
- }
- }
- }
客户端逻辑
1. 建立socketChannel 连接到对应的端口
2. 新建selector对象,然后把socketChannel注册到selector上
3. 建立死循环 ,监听是否有事件发生,若有,则遍历seletionKey set ,
4. 判断发生的事件是什么,
5. 如果是连接事件 ,做对应的连接处理,注册读事件
- 判断是否在等待连接 ,在进程中
- if (channel.isConnectionPending()) {
- channel.finishConnect(); 完成连接,这里是阻塞的
6. 如果发生了读事件,读取数据
- import java.io.BufferedReader;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.SocketChannel;
- import java.time.LocalDateTime;
- import java.util.Iterator;
- import java.util.Set;
- import java.util.concurrent.Executor;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ThreadFactory;
- public class NioClient {
- public static void main(String[] args) {
- try{
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.configureBlocking(false);
- socketChannel.connect(new InetSocketAddress(8899));//服务端就是bind 然后accept serverSocketChannel
- Selector selector = Selector.open();
- socketChannel.register(selector, SelectionKey.OP_CONNECT);//注册连接事件
- while(true) {
- int number = selector.select();
- if(number > 0) {
- Set<SelectionKey> selectionKeySet = selector.selectedKeys();
- Iterator<SelectionKey> iterable = selectionKeySet.iterator();
- while(iterable.hasNext()) {//有事件发生
- SelectionKey selectionKey = iterable.next();
- SocketChannel client = (SocketChannel) selectionKey.channel();
- if(selectionKey.isConnectable()) {//判断 selectionkey 状态 可连接的
- if(client.isConnectionPending()) {//是否在准备连接的进程中
- client.finishConnect();//这里会阻塞,如果连接未建立,抛异常 ,
- ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
- byteBuffer.put((LocalDateTime.now() + ",连接成功").getBytes());
- byteBuffer.flip();
- client.write(byteBuffer);
- ExecutorService executorService = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
- executorService.submit(() -> {//起一个新的线程,去接收控制台的输入 ,不影响其他线程
- while(true) {
- try{
- byteBuffer.clear();
- InputStreamReader inputStreamReader = new InputStreamReader(System.in);
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
- byteBuffer.put(bufferedReader.readLine().getBytes());
- byteBuffer.flip();
- client.write(byteBuffer);
- }catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
- iterable.remove();//这个事件清楚,很关键
- client.register(selector, SelectionKey.OP_READ);//注册读事件
- } else if(selectionKey.isReadable()){//可读取
- SocketChannel socketChannel1 = (SocketChannel) selectionKey.channel();
- ByteBuffer readBuffer = ByteBuffer.allocate(1024);
- int readCount = socketChannel.read(readBuffer);
- if(readCount > 0) {
- String receiveMsg = new String(readBuffer.array());
- System.out.println("receiveMsg : " + receiveMsg);
- }
- iterable.remove();
- }
- }
- }
- }
- }catch (Exception e ) {
- e.printStackTrace();
- }
- }
- }
3、nio中的selector使用的更多相关文章
- epoll浅析以及nio中的Selector
出处: https://my.oschina.net/hosee/blog/730598 首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference) ...
- epoll 浅析以及 nio 中的 Selector
首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference): 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作 ...
- Java I/O(4):AIO和NIO中的Selector
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在Java NIO的三大核心中,除了Channel和Buffer,剩下的就是Selector了.有的地方叫它选择器,也有叫多路复用器的(比如Ne ...
- NIO中Selector分析
NIO中,使用Selector.select()方法来侦听是否有数据可以读/写,服务端开始执行时,如果没有客户端,这里的语句将进行阻塞,等待下面三个情况出现,才会进行后续的方法之行,这里是重点 ...
- 【Java】NIO中Selector的select方法源码分析
该篇博客的有些内容和在之前介绍过了,在这里再次涉及到的就不详细说了,如果有不理解请看[Java]NIO中Channel的注册源码分析, [Java]NIO中Selector的创建源码分析 Select ...
- Java NIO中核心组成和IO区别
1.Java NIO核心组件 Java NIO中有很多类和组件,包括Channel,Buffer 和 Selector 构成了核心的API.其它组件如Pipe和FileLock是与三个核心组件共同使用 ...
- 两种 NIO 实现:Selector 与 Epoll
[总结]两种 NIO 实现:Selector 与 Epoll 时间2012-11-17 08:38:42 开源中国新闻原文 http://my.oschina.net/ielts0909/blog/ ...
- 7. 彤哥说netty系列之Java NIO核心组件之Selector
--日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇. 简介 上一章我们一起学习了Java NIO的核心组件Buffer,它通常跟Channel一起使用,但是它们在网络IO中又该如何 ...
- 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?
原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...
随机推荐
- UITableView 实例详解 滑动编辑 headerView
转自:http://blog.csdn.net/reylen/article/details/8505960 self.dataArray = [[[NSMutableArray alloc]init ...
- python 金融应用(一)期权定价公式的计算
一.基于不付息的欧式期权看涨BSM公式 假定股票服从下列微分方程: 期权定价公式: 二.蒙特卡洛模拟 import numpy as np import math from time import t ...
- 写入Apache Hudi数据集
这一节我们将介绍使用DeltaStreamer工具从外部源甚至其他Hudi数据集摄取新更改的方法, 以及通过使用Hudi数据源的upserts加快大型Spark作业的方法. 对于此类数据集,我们可以使 ...
- Day 03 Python 基础
目录 Pycharm 的使用 设置 快捷键 变量 什么是变量 定义变量 变量名的命名规则 变量名的两种命名方式 注释 快捷键(快速注释) 单行注释 多行注释 注释的作用 Turtle库的使用 Pych ...
- 前端表单提交,提交有图片出现的问题,及解决方案 兼容ie9
更新一下我的小园子,主要说的是jq文件上传的过程中,如果出现上传的文件里有图片问题 其实文件上传有图片的情况下,不是什么大问题,对于前端来说,但是,如果需要兼容ie9的时候,就需要处理一下 文件上传如 ...
- 3个Spring Boot核心注解,你知道几个?
Spring Boot 核心注解讲解 Spring Boot 最大的特点是无需 XML 配置文件,能自动扫描包路径装载并注入对象,并能做到根据 classpath 下的 jar 包自动配置. 所以 S ...
- 4个点说清楚Java中synchronized和volatile的区别
作者 : Hollis 回顾一下两个关键字:synchronized和volatile 1.Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如sy ...
- pipelinedb 常用sql语句
-- 创建普通表create table simple_user (name varchar(80), age int , phone varchar(30), birthday date ); -- ...
- IDEA+Maven 整合SSM框架实现简单的增删改查(新手入门,傻瓜操作)
原博客地址:https://blog.csdn.net/khxu666/article/details/79851070 选用SSM框架的原因在目前的企业级Java应用中,Spring框架是必须的.S ...
- Python之工作方向
"python基础-->(函数/面向对象/网络编程(scoket套接字)/并发编程(mutiprocessing)) "运维+web开发-->页面展示(django/f ...