通过编写一个客户端和服务器端的例子来熟悉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使用的更多相关文章

  1. epoll浅析以及nio中的Selector

    出处: https://my.oschina.net/hosee/blog/730598 首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference) ...

  2. epoll 浅析以及 nio 中的 Selector

    首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference): 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作 ...

  3. Java I/O(4):AIO和NIO中的Selector

    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在Java NIO的三大核心中,除了Channel和Buffer,剩下的就是Selector了.有的地方叫它选择器,也有叫多路复用器的(比如Ne ...

  4. NIO中Selector分析

        NIO中,使用Selector.select()方法来侦听是否有数据可以读/写,服务端开始执行时,如果没有客户端,这里的语句将进行阻塞,等待下面三个情况出现,才会进行后续的方法之行,这里是重点 ...

  5. 【Java】NIO中Selector的select方法源码分析

    该篇博客的有些内容和在之前介绍过了,在这里再次涉及到的就不详细说了,如果有不理解请看[Java]NIO中Channel的注册源码分析, [Java]NIO中Selector的创建源码分析 Select ...

  6. Java NIO中核心组成和IO区别

    1.Java NIO核心组件 Java NIO中有很多类和组件,包括Channel,Buffer 和 Selector 构成了核心的API.其它组件如Pipe和FileLock是与三个核心组件共同使用 ...

  7. 两种 NIO 实现:Selector 与 Epoll

    [总结]两种 NIO 实现:Selector 与 Epoll 时间2012-11-17 08:38:42 开源中国新闻原文  http://my.oschina.net/ielts0909/blog/ ...

  8. 7. 彤哥说netty系列之Java NIO核心组件之Selector

    --日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇. 简介 上一章我们一起学习了Java NIO的核心组件Buffer,它通常跟Channel一起使用,但是它们在网络IO中又该如何 ...

  9. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...

随机推荐

  1. 洛谷 P3420 [POI2005]SKA-Piggy Banks 题解

    蒟蒻的第二篇题解 嗯,直接进入正题 先告诉你们这是并查集,好吧,标签上面有,再来分析这为什么是并查集. 根据题意: 每一个存钱罐能够用相应的钥匙打开或者被砸开,Byteazar已经将钥匙放入到一些存钱 ...

  2. 记录我的 python 学习历程-Day03 列表/元组/rang

    一.列表初识 列表是 Python 的基础数据类型之一,它是以''[ ]''的形式括起来的,每个元素用","隔开,属于容器型数据类型,他可以存放大量的.各种类型的数据. 基本格式 ...

  3. Table表格滑过当前项[当前行][当前列]对应高亮

    效果演示图: JS 代码如下: function TableHover($table){       $table.mouseenter(function(event) {            va ...

  4. 基于iCamera测试500w摄像头-mt9p001,mt9p031,mt9p001模块小结 续2

    本次使用单色版本,镜头使用近焦镜头,拍摄大约30cm以内的物体和图像 更多原始图像效果,请关注百度云盘 http://pan.baidu.com/s/1cumqia

  5. Python自动输入【新手必学】

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:哈喽哈嘿哈 这篇文章是我的第一篇文章,写的不好的地方,请大家多多指教哈 ...

  6. java中小数点位数

    import java.math.BigDecimal;import java.text.DecimalFormat;import java.text.NumberFormat;import java ...

  7. Linux常见指令大全

    转载自https://www.cnblogs.com/caozy/p/9261224.html 前言 本文特点 授之以渔:了解命令学习方法.用途:不再死记硬背,拒绝漫无目的: 准确无误:所有命令执行通 ...

  8. 在 VSCode 中 Angular 的字符串报错的问题

    使用 Angular 时,报错 [tslint] " should be ' 报错原因是因为 ESLint 的严格模式,限制了使用 ' ,甚至多一个空格都会报错. 我们只需要在 settin ...

  9. The Preliminary Contest for ICPC Asia Xuzhou 2019

    A:Who is better? 题目链接:https://nanti.jisuanke.com/t/41383 题意: 类似于有N个石子,先手第一次不能拿完,每次后手只能拿 1 到 前一次拿的数量* ...

  10. 《CSAPP》实验二:二进制炸弹

    二进制炸弹是第三章<程序的机器级表示>的配套实验,这章主要介绍了x64汇编,包括:操作数的表示方式,数据传送指令,算术和逻辑指令,控制流跳转指令,过程(procedure)的实现与运行时栈 ...