通过编写一个客户端和服务器端的例子来熟悉selector的使用

服务端逻辑:

1. 绑定一个端口号
2. channel注册到selector中
3. 用死循环来监听如果有时间发生,遍历selectionKey set
4. 判断发生的事件类型,前面会注册accept事件,如果发生accept事件,那么注册读事件,同时清除selectionKey set 中的当前元素。、
5. 接收事件时,将channel保存下来。
6. 发生读事件时,说明有信息,发过来了,那么将消息,转发给所有的客户端。然后清除自身的事件。

  1. import java.io.IOException;
  2. import java.net.InetSocketAddress;
  3. import java.net.ServerSocket;
  4. import java.nio.ByteBuffer;
  5. import java.nio.channels.SelectionKey;
  6. import java.nio.channels.Selector;
  7. import java.nio.channels.ServerSocketChannel;
  8. import java.nio.channels.SocketChannel;
  9. import java.nio.charset.Charset;
  10. import java.util.*;
  11.  
  12. public class NioServer {
  13.  
  14. private static HashMap<String, SocketChannel> clientMap = new HashMap<String, SocketChannel>();
  15.  
  16. public static void main(String[] args) throws IOException {
  17. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  18. serverSocketChannel.configureBlocking(false);
  19.  
  20. ServerSocket serverSocket = serverSocketChannel.socket();
  21. serverSocket.bind(new InetSocketAddress(8899));
  22.  
  23. Selector selector = Selector.open();
  24.  
  25. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  26.  
  27. while(true) {
  28. int number = selector.select();
  29. // System.out.println("number:" + number);
  30. Set<SelectionKey> selectionKeySet = selector.selectedKeys();
  31.  
  32. Iterator<SelectionKey> iterable = selectionKeySet.iterator();
  33.  
  34. if(number > 0 ) {
  35. while(iterable.hasNext()) {
  36. SelectionKey selectionKey = iterable.next();
  37.  
  38. if(selectionKey.isAcceptable()) {//如果是可接收连接的
  39. ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
  40. SocketChannel socketChannel = ssc.accept();
  41. socketChannel.configureBlocking(false);
  42.  
  43. socketChannel.register(selector, SelectionKey.OP_READ);//注册读事件
  44.  
  45. clientMap.put(UUID.randomUUID() + "", socketChannel);//保存下channel
  46.  
  47. iterable.remove();
  48. } else if(selectionKey.isReadable()){//可读的
  49. SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
  50. ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  51.  
  52. int readCount = socketChannel.read(byteBuffer);
  53.  
  54. //这里本该用while
  55. if(readCount > 0 ) {//读取到数据,就写回到其他客户端
  56. byteBuffer.flip();
  57.  
  58. Charset charset = Charset.forName("UTF-8");
  59. String receiveStr = new String(charset.decode(byteBuffer).array());
  60.  
  61. System.out.println(socketChannel + " receive msg :" + receiveStr);
  62.  
  63. String sendKey = "";
  64.  
  65. for(Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {//第一遍遍历找到发送者
  66. if(socketChannel == entry.getValue()) {
  67. sendKey = entry.getKey();
  68. break;
  69. }
  70. }
  71.  
  72. for (Map.Entry<String, SocketChannel> entry: clientMap.entrySet() ) {//给每个保存的连接,都发送消息
  73. ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
  74. writeBuffer.put((sendKey + ":" + receiveStr).getBytes());
  75.  
  76. writeBuffer.flip();
  77. entry.getValue().write(writeBuffer);
  78. }
  79. }
  80. iterable.remove();//这个 删除很关键 每次循环完selectionKeySet ,一定要清楚事件,不然肯定会影响下一次的事件触发,或者直接不触发下次的事件
  81. }
  82. }
  83. }
  84.  
  85. }
  86. }
  87. }

客户端逻辑

1. 建立socketChannel 连接到对应的端口
2. 新建selector对象,然后把socketChannel注册到selector上
3. 建立死循环 ,监听是否有事件发生,若有,则遍历seletionKey set ,
4. 判断发生的事件是什么,
5. 如果是连接事件 ,做对应的连接处理,注册读事件

  1. 判断是否在等待连接 ,在进程中
  2. if (channel.isConnectionPending()) {
  3. channel.finishConnect(); 完成连接,这里是阻塞的

6. 如果发生了读事件,读取数据

  1. import java.io.BufferedReader;
  2. import java.io.InputStream;
  3. import java.io.InputStreamReader;
  4. import java.net.InetSocketAddress;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.SelectionKey;
  7. import java.nio.channels.Selector;
  8. import java.nio.channels.SocketChannel;
  9. import java.time.LocalDateTime;
  10. import java.util.Iterator;
  11. import java.util.Set;
  12. import java.util.concurrent.Executor;
  13. import java.util.concurrent.ExecutorService;
  14. import java.util.concurrent.Executors;
  15. import java.util.concurrent.ThreadFactory;
  16.  
  17. public class NioClient {
  18.  
  19. public static void main(String[] args) {
  20. try{
  21. SocketChannel socketChannel = SocketChannel.open();
  22. socketChannel.configureBlocking(false);
  23. socketChannel.connect(new InetSocketAddress(8899));//服务端就是bind 然后accept serverSocketChannel
  24.  
  25. Selector selector = Selector.open();
  26.  
  27. socketChannel.register(selector, SelectionKey.OP_CONNECT);//注册连接事件
  28.  
  29. while(true) {
  30. int number = selector.select();
  31.  
  32. if(number > 0) {
  33. Set<SelectionKey> selectionKeySet = selector.selectedKeys();
  34.  
  35. Iterator<SelectionKey> iterable = selectionKeySet.iterator();
  36. while(iterable.hasNext()) {//有事件发生
  37. SelectionKey selectionKey = iterable.next();
  38.  
  39. SocketChannel client = (SocketChannel) selectionKey.channel();
  40. if(selectionKey.isConnectable()) {//判断 selectionkey 状态 可连接的
  41. if(client.isConnectionPending()) {//是否在准备连接的进程中
  42. client.finishConnect();//这里会阻塞,如果连接未建立,抛异常 ,
  43.  
  44. ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  45.  
  46. byteBuffer.put((LocalDateTime.now() + ",连接成功").getBytes());
  47. byteBuffer.flip();
  48. client.write(byteBuffer);
  49.  
  50. ExecutorService executorService = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
  51.  
  52. executorService.submit(() -> {//起一个新的线程,去接收控制台的输入 ,不影响其他线程
  53. while(true) {
  54. try{
  55. byteBuffer.clear();
  56. InputStreamReader inputStreamReader = new InputStreamReader(System.in);
  57. BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
  58.  
  59. byteBuffer.put(bufferedReader.readLine().getBytes());
  60. byteBuffer.flip();
  61. client.write(byteBuffer);
  62.  
  63. }catch (Exception e) {
  64. e.printStackTrace();
  65. }
  66. }
  67. });
  68. }
  69.  
  70. iterable.remove();//这个事件清楚,很关键
  71. client.register(selector, SelectionKey.OP_READ);//注册读事件
  72. } else if(selectionKey.isReadable()){//可读取
  73. SocketChannel socketChannel1 = (SocketChannel) selectionKey.channel();
  74. ByteBuffer readBuffer = ByteBuffer.allocate(1024);
  75.  
  76. int readCount = socketChannel.read(readBuffer);
  77. if(readCount > 0) {
  78. String receiveMsg = new String(readBuffer.array());
  79. System.out.println("receiveMsg : " + receiveMsg);
  80. }
  81.  
  82. iterable.remove();
  83. }
  84.  
  85. }
  86. }
  87. }
  88.  
  89. }catch (Exception e ) {
  90. e.printStackTrace();
  91. }
  92.  
  93. }
  94. }

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. UITableView 实例详解 滑动编辑 headerView

    转自:http://blog.csdn.net/reylen/article/details/8505960 self.dataArray = [[[NSMutableArray alloc]init ...

  2. python 金融应用(一)期权定价公式的计算

    一.基于不付息的欧式期权看涨BSM公式 假定股票服从下列微分方程: 期权定价公式: 二.蒙特卡洛模拟 import numpy as np import math from time import t ...

  3. 写入Apache Hudi数据集

    这一节我们将介绍使用DeltaStreamer工具从外部源甚至其他Hudi数据集摄取新更改的方法, 以及通过使用Hudi数据源的upserts加快大型Spark作业的方法. 对于此类数据集,我们可以使 ...

  4. Day 03 Python 基础

    目录 Pycharm 的使用 设置 快捷键 变量 什么是变量 定义变量 变量名的命名规则 变量名的两种命名方式 注释 快捷键(快速注释) 单行注释 多行注释 注释的作用 Turtle库的使用 Pych ...

  5. 前端表单提交,提交有图片出现的问题,及解决方案 兼容ie9

    更新一下我的小园子,主要说的是jq文件上传的过程中,如果出现上传的文件里有图片问题 其实文件上传有图片的情况下,不是什么大问题,对于前端来说,但是,如果需要兼容ie9的时候,就需要处理一下 文件上传如 ...

  6. 3个Spring Boot核心注解,你知道几个?

    Spring Boot 核心注解讲解 Spring Boot 最大的特点是无需 XML 配置文件,能自动扫描包路径装载并注入对象,并能做到根据 classpath 下的 jar 包自动配置. 所以 S ...

  7. 4个点说清楚Java中synchronized和volatile的区别

    作者 : Hollis 回顾一下两个关键字:synchronized和volatile 1.Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如sy ...

  8. pipelinedb 常用sql语句

    -- 创建普通表create table simple_user (name varchar(80), age int , phone varchar(30), birthday date ); -- ...

  9. IDEA+Maven 整合SSM框架实现简单的增删改查(新手入门,傻瓜操作)

    原博客地址:https://blog.csdn.net/khxu666/article/details/79851070 选用SSM框架的原因在目前的企业级Java应用中,Spring框架是必须的.S ...

  10. Python之工作方向

    "python基础-->(函数/面向对象/网络编程(scoket套接字)/并发编程(mutiprocessing)) "运维+web开发-->页面展示(django/f ...