• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Java-NIO-Selector

武飞扬头像
想养一只萨摩耶~
帮助1

目录

1 概述

2 Selector

2.1 可选择通道(SelectableChannel)

2.2 选择键 (SelectionKey)

2.3  方法示例

2.4 停止选择的方法

3 Selector演示小demo


1 概述

        Selector一般称之为选择器,也可以翻译为多路复用器。它是Java-NIO中核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可实现单线程管理多个channels,也就是可以管理多个网络连接。

使用Selector的好处在于:使用更少的线程来就可以处理通道了,相比使用多个线程,避免了线程上下文切换带来的开销

2 Selector

2.1 可选择通道(SelectableChannel)

1)不是所有的Channel都能够被Selector复用的。像FileChannel就不能被选择器复用(因为它没有继承SelectableChannel).只有继承了SelectableChannel才能够被Selector复用。

2)SelectableChannel类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的通道类的父类。所有的socket通道,都继承了SelectableChannel类都是可选择的,包括从管道(pipe)对象中或得的通道。而FileChannel类,没有继承SelectableChannel所以不是可选择通道。

3)一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。通道和选择器之间的关系使用注册的方式完成

学新通

2.2 选择键 (SelectionKey)

1)Channel注册到后,并且一旦通道处于某种就绪的状态,就可以被选择器查询到。这个工作,使用选择器Selector的select()方法完成。select方法的作用,对感兴趣的通道操作,进行就绪状态的查询。

2)Selector可以不断查询Channel中发生的操作的就绪状态。并且挑选感兴趣的操作就绪状态。一旦通道有操作的就绪状态打成,并且是感兴趣的操作,就会被Selector选中,放进选择键集合

3)一个选择键,首先是包含了注册在Selector的通道操作的类型。也包含的特定的通道与特定的选择器之间的注册关系。

4)选择键的概念,和事件的概念比较相似。一个选择键类似于监听模式里边的一个事件。由于Selector不是事件触发的模式而是主动去查询的模式,所以不叫事件event ,而是叫SelectionKey选择键。

2.3  方法示例

  1.  
    public static void main(String[] args) throws IOException {
  2.  
     
  3.  
    //创建selector
  4.  
    Selector selector = Selector.open();
  5.  
     
  6.  
    //通道
  7.  
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  8.  
     
  9.  
    //非阻塞
  10.  
    serverSocketChannel.configureBlocking(false);
  11.  
     
  12.  
    //绑定连接
  13.  
    serverSocketChannel.bind(new InetSocketAddress(9999));
  14.  
     
  15.  
    //将通道注册到选择器上
  16.  
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  17.  
     
  18.  
    //查询已经就绪通道操作
  19.  
    Set<SelectionKey> selectionKeys = selector.selectedKeys();
  20.  
    //遍历集合
  21.  
    Iterator<SelectionKey> iterator = selectionKeys.iterator();
  22.  
    while (iterator.hasNext()) {
  23.  
    SelectionKey key = iterator.next();
  24.  
    //判断key就绪状态操作
  25.  
    if (key.isAcceptable()) {
  26.  
     
  27.  
    }else if (key.isConnectable()){
  28.  
     
  29.  
    }else if (key.isReadable()){
  30.  
     
  31.  
    }else if (key.isWritable()) {
  32.  
     
  33.  
    }
  34.  
    }
  35.  
    iterator.remove();
  36.  
     
  37.  
    }

2.4 停止选择的方法

选择器执行选择的过程,系统底层会依次询问每个通道是否就绪,这个过程可能会造成调用线程进入阻塞状态,那么有以下方法可以唤醒select()方法中阻塞的线程

1)wakeup() 方法:通过调用Selector对象的wakeup()方法让处在阻塞状态下selector()立刻返回。该方法使得选择器上的第一个还没返回的选择操作立即返回。如果当前没有进行中的选择操作,那么下一次对selector()方法的一次调用将立即返回。

2)close()方法:通过close()方法关闭Selector。该方法使得任何一个在选择操作中阻塞的线程都被唤醒,同时使得注册到该Selector的所有Channel被注销,所有的建都会取消,但是channel本身不会关闭

3 Selector演示小demo

先启动服务端,在启动main方法

  1.  
    public static void main(String[] args) throws IOException {
  2.  
    //获取通道 绑定主机和端口号
  3.  
    SocketChannel socketChannel =
  4.  
    SocketChannel.open(new InetSocketAddress("127.0.0.1", 8080));
  5.  
    //切换到非阻塞模式
  6.  
    socketChannel.configureBlocking(false);
  7.  
    //创建buffer
  8.  
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  9.  
    Scanner scanner = new Scanner(System.in);
  10.  
    while (scanner.hasNext()) {
  11.  
    String str = scanner.next();
  12.  
    //写入buffer数据
  13.  
    byteBuffer.put((new Date().toString() "--->" str).getBytes());
  14.  
    //模式切换
  15.  
    byteBuffer.flip();
  16.  
    //写入通道
  17.  
    socketChannel.write(byteBuffer);
  18.  
    //关闭
  19.  
    byteBuffer.clear();
  20.  
     
  21.  
    }
  22.  
    }
  23.  
     
  24.  
     
  25.  
    @Test
  26.  
    public void Server() throws IOException {
  27.  
    //获取服务端通道
  28.  
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  29.  
     
  30.  
    //切换到非阻塞模式
  31.  
    serverSocketChannel.configureBlocking(false);
  32.  
    //创建buffer
  33.  
    ByteBuffer serverByteBuffer = ByteBuffer.allocate(1024);
  34.  
    //绑定端口号
  35.  
    serverSocketChannel.bind(new InetSocketAddress(8080));
  36.  
    //获取selector选择器
  37.  
    Selector selector = Selector.open();
  38.  
    //通道注册到选择器,进行监听 参数1:选择器 参数2:感兴趣的事情
  39.  
    serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
  40.  
    //选择器进行轮询 进行后续操作
  41.  
    while (selector.select() > 0 ) {
  42.  
    Set<SelectionKey> selectionKeys = selector.selectedKeys();
  43.  
    Iterator<SelectionKey> selectionKeysIterator = selectionKeys.iterator();
  44.  
    while (selectionKeysIterator.hasNext()) {
  45.  
    //查询就绪操作
  46.  
    SelectionKey next = selectionKeysIterator.next();
  47.  
    //判断什么操作
  48.  
    if (next.isAcceptable()) {
  49.  
    //获取到连接
  50.  
    SocketChannel accept = serverSocketChannel.accept();
  51.  
    //切换非阻塞模式
  52.  
    accept.configureBlocking(false);
  53.  
    //注册
  54.  
    accept.register(selector,SelectionKey.OP_READ);
  55.  
    }else if (next.isReadable()){
  56.  
    SocketChannel channel = (SocketChannel)next.channel();
  57.  
    //创建buffer
  58.  
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  59.  
    //读取数据
  60.  
    int length = 0;
  61.  
    while ((length = channel.read(byteBuffer)) > 0 ) {
  62.  
    byteBuffer.flip();
  63.  
    System.out.println(new String(byteBuffer.array(),0,length));
  64.  
    byteBuffer.clear();
  65.  
    }
  66.  
     
  67.  
    }
  68.  
    }
  69.  
    selectionKeysIterator.remove();
  70.  
    }
  71.  
    }

在客户端输入:

学新通

 服务端接收:

学新通

        

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgakjaa
系列文章
更多 icon
同类精品
更多 icon
继续加载