zoukankan      html  css  js  c++  java
  • Java NIO (四) 选择器(Selector)

    Java NIO (四) 选择器(Selector)

    选择器(Selector) 是 SelectableChannle 对象的多路复用器,Selector 可以同时监控多个 SelectableChannel 的 IO 状况,也就是说,利用 Selector可使一个单独的线程管理多个 Channel,selector 是非阻塞 IO 的核心。

    SelectableChannle 的继承树如下图:

    选择器(Selector)的应用:

    当通道使用register(Selector sel, int ops)方法将通道注册选择器时,选择器对通道事件进行监听,通过第二个参数指定监听的事件类型。

    其中可监听的事件类型包括以下:

      读 : SelectionKey.OP_READ (1)

      写 : SelectionKey.OP_WRITE (4)

      连接 : SelectionKey.OP_CONNECT (8)

      接收 : SelectionKey.OP_ACCEPT (16)

    如果需要监听多个事件是:

      int key = SelectionKey.OP_READ | SelectionKey.OP_WRITE ; //表示同时监听读写操作

    如何应用请看代码:

    复制代码

    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.util.Iterator;
    import java.util.Set;

    /**
    * Created by 58 on 2016/11/28.
    */
    public class SelectorServer {
    public static void main(String args[]){
    startServer();
    }
    public static ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
    public static ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);

    public static void startServer(){
    //用两个channel监听两个端口
    int listenPort = 8888;
    int listenPort1 = 8889;
    sendBuffer.put("message from server".getBytes());

    try {
    //创建serverchannel,绑定对应的端口
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    ServerSocket serverSocket = serverSocketChannel.socket();
    InetSocketAddress inetSocketAddress = new InetSocketAddress(listenPort);
    serverSocket.bind(inetSocketAddress);

    //创建第二个channel
    ServerSocketChannel serverSocketChannel1 = ServerSocketChannel.open();
    ServerSocket serverSocket1 = serverSocketChannel1.socket();
    InetSocketAddress inetSocketAddress1 = new InetSocketAddress(listenPort1);
    serverSocket1.bind(inetSocketAddress1);


    //创建selector对象
    Selector selector = Selector.open();

    //设置channel注册到selector中
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    //第二个channel
    serverSocketChannel1.configureBlocking(false);
    serverSocketChannel1.register(selector, SelectionKey.OP_ACCEPT);

    System.out.println("start to listen port: " + listenPort);
    System.out.println("start to listen port: " + listenPort1);

    //监听端口
    while(true){
    int readyChannels = selector.select();
    if(readyChannels == 0)
    continue;
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> iterator = selectedKeys.iterator();
    while(iterator.hasNext()){
    SelectionKey selectionKey = iterator.next();
    dealSelectionKey(selector, selectionKey);

    iterator.remove();
    }//while
    }//while


    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    public static void dealSelectionKey(Selector selector, SelectionKey selectionKey){
    try{
    //准备好接收新的连接
    if(selectionKey.isAcceptable()){
    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
    SocketChannel clientSocketChannel = serverSocketChannel.accept();
    clientSocketChannel.configureBlocking(false);
    clientSocketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
    System.out.println("channel is ready acceptable");
    }
    else if(selectionKey.isConnectable()){
    selectionKey.channel().register(selector, SelectionKey.OP_READ);
    System.out.println("channel is connectable.");
    }
    else if(selectionKey.isReadable()){
    //读去客户端内容
    SocketChannel clientSocketChannel = (SocketChannel) selectionKey.channel();
    receiveBuffer.clear();
    clientSocketChannel.read(receiveBuffer);
    selectionKey.interestOps(SelectionKey.OP_WRITE);
    System.out.println("message from client is: " + new String(receiveBuffer.array()));
    System.out.println("Thread id : " + Thread.currentThread().getId());
    }
    else if(selectionKey.isWritable()){
    //向客户端写数据
    SocketChannel clientSocketChannel = (SocketChannel) selectionKey.channel();
    sendBuffer.flip();
    System.out.println("sendBuffer = " + new String(sendBuffer.array()));
    clientSocketChannel.write(sendBuffer);
    selectionKey.interestOps(SelectionKey.OP_READ);
    System.out.println("channle is writable.");
    }//else if
    }catch (Exception e){

    }
    }
    }

    client:

    import java.io.IOException;
    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.util.Iterator;
    import java.util.Set;

    /**
    * Created by 58 on 2016/11/28.
    */
    public class SelectorClient {
    public static void main(String args[]){
    work();
    }

    public static void work(){
    int serverPort = 8888;
    ByteBuffer sendBuffer = ByteBuffer.wrap("client message".getBytes());
    ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
    try {
    //创建通道,设置通道注册到selector中
    SocketChannel socketChannel = SocketChannel.open();
    Selector selector = Selector.open();

    socketChannel.configureBlocking(false);
    socketChannel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
    socketChannel.connect(new InetSocketAddress("localhost", serverPort));
    int executeTimes = 2;
    //while
    while(executeTimes > 0){
    executeTimes--;
    int reayChannelNum = selector.select();
    if(reayChannelNum == 0){
    continue;
    }
    Set<SelectionKey> setOfSelectionKey = selector.selectedKeys();
    Iterator<SelectionKey> iterator = setOfSelectionKey.iterator();
    while(iterator.hasNext()){
    SelectionKey selectionKey = iterator.next();
    SocketChannel socketChannel1 = (SocketChannel) selectionKey.channel();
    iterator.remove();
    if(selectionKey.isConnectable()){
    if(socketChannel1.isConnectionPending()){
    socketChannel1.finishConnect();
    System.out.println("connection complete.");
    socketChannel1.write(sendBuffer);
    }
    }//if isConnectable
    else if(selectionKey.isReadable()){
    receiveBuffer.clear();
    socketChannel1.read(receiveBuffer);
    receiveBuffer.flip();
    System.out.println("message from server: " + new String(receiveBuffer.array()));

    }//else if readable
    else if(selectionKey.isWritable()){
    sendBuffer.flip();
    socketChannel1.write(sendBuffer);
    }
    }
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    复制代码

    NIO的非阻塞性:

    nio的非阻塞是对于网络通道来说的,需要使用Channel.configureBlocking(false)来设置通道为非阻塞的,如果没设置,默认是阻塞的。

  • 相关阅读:
    数据库子句
    数据查询的语言
    试图
    Bootstrap 简介及引用方法
    一阶段项目整理
    js 鼠标移入移出
    js 鼠标点击事件
    轮播图
    滚动条 固定导航栏
    三元运算符 DOM找元素
  • 原文地址:https://www.cnblogs.com/handsome1013/p/7475087.html
Copyright © 2011-2022 走看看