NIO学习(三)----Selector

NIO学习(一)----Buffer
NIO学习(二)----Channel
NIO学习(三)----Selector
NIO学习(四)----DatagramChannel和管道(pipe)

选择器(Selector)

1.选择器(Selector)是SelectableChannl对象的多路复用器,Selector可以同时监控多个SelectableChannel的IO状况,利用Selector可使一个单独的线程管理多个Channel。Selector是非阻塞IO的核心。
2.SelectableChannel的结构如下图:
在这里插入图片描述

选择器(Selector)的应用

1.创建Selector通过调用Selector.open()方法创建一个Selector
//4.获取选择器
Selector selector = Selector.open();
2.向选择器注册通道:SelectableChannel.regiter(Selector sel,int ops)
//1.获取通道
ServerSocketChannel sSChannel = ServerSocketChannel.open();
//2.切换非阻塞
sSChannel.configureBlocking(false);
//3.绑定连接
sSChannel.bind(new InetSocketAddress(8099));
//4.获取选择器
Selector selector = Selector.open();
//5.将通道注册到选择器上
sSChannel.register(selector, SelectionKey.OP_READ)

选择器(Selector)的应用

1.当调用register(Selector sel,int ops)将通道注册选择器时,选择器对通道的监听事件,需要通过第二个参数ops指定
2.可以监听的事件类型(可使用SelectionKey的四个变量表示):
1)读:SelectionKey.OP_READ (1)
2)写:SelectionKey.OP_WRITE(4)
3)连接:SelectionKey.OP_CONNECT(8)
4)接收:SelectionKey.OP_ACCEPT(16)
3.诺注册时不止监听一个事件,则可以使用“位或”操作符连接
例如:
//注册“监听事件”
int interesSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

Selection Key

SelectionKey:表示SelectableChannel和Selector之间的注册关系。每次向注册器注册通道时就会选择一个事件(选择键)。选择键包含两个表示为整数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作。
方法 描述
Int interestOps() 获取感兴趣事件集合
Int readyOps() 获取通道已经就绪的操作的合集
SelectableChannel channel() 获取注册通道
Selector selector() 返回注册器
Boolean isReadable() 检测channal中都读事件是否就绪
Boolean isWritable() 检测channal中都写事件是否就绪
Boolean isConnectable() 检测channal中都连接是否就绪
Boolean isAcceptable() 检测channal中都接收是否就绪

NonBlockingNIO

package com.wxl.nio;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;

/*
 * 一、使用NIO完成网络通信的三个核心
 *
 * 1.通道(Channel):负责连接
 *
 *   java.nio.channels.Channel 接口:
 *       |--SelectableChannel
 *           |--SocketChannel                tcp
 *           |--ServerSocketChannel  `       tcp
 *           |--DatagramChannel              udp
 *
 *           |--Pipe.SinkChannel
 *           |--Pipe.SourceChannel
 *
 * 2.缓冲区(Buffer):负责数据的存储
 *
 * 3.选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况
 * */
public class TestNonBlockingNIO {

//客户端
@Test
public void Client(){
    try {
        //1.获取通道
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8099));
        //2.切换非阻塞模式
        sChannel.configureBlocking(false);
        //3.分配指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        //4.发送数据给服务器
//            Scanner scan = new Scanner(System.in);
//            while (scan.hasNext()) {
//                String str =scan.next();
//                buf.put((new Date().toString()+"\n"+str).getBytes());
            buf.put((new Date().toString()).getBytes());
            buf.flip();
            sChannel.write(buf);
            buf.clear();
//            }
        //5.关闭通道
        sChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//服务端
@Test
public void Server(){
    try {
        //1.获取通道
        ServerSocketChannel sSChannel = ServerSocketChannel.open();
        //2.切换非阻塞
        sSChannel.configureBlocking(false);
        //3.绑定连接
        sSChannel.bind(new InetSocketAddress(8099));
        //4.获取选择器
        Selector selector = Selector.open();
        //5.将通道注册到选择器上,并且指定“监听接收事件”
        sSChannel.register(selector, SelectionKey.OP_ACCEPT);

        //6.轮询式的获取选择器上已经“准备就绪”的事件
        while (selector.select()>0){
            //7.获取选择器中所有注册的“选择键(已就绪的监听事件)"
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()){
                //8.获取准备”就绪“的事件
                SelectionKey sk = it.next();
                //9.判断具体是什么事件准备就绪
                if (sk.isAcceptable()){
                    //10.诺“接收就绪",获取客户端连接
                    SocketChannel sChannel = sSChannel.accept();
                    //11.切换非阻塞模式
                    sChannel.configureBlocking(false);
                    //12.将该通道注册到选择器上
                    sChannel.register(selector,SelectionKey.OP_READ);
                }else if (sk.isReadable()){
                    //13.获取当前选择器上“读就绪”状态的通道
                    SocketChannel sChannel = (SocketChannel) sk.channel();
                    //14.读取数据
                    ByteBuffer buf = ByteBuffer.allocate(1024);

                    int len = 0;
                    while((len = sChannel.read(buf))>0){
                        buf.flip();
                        System.out.println(new String(new String(buf.array(),0,len)));
                        buf.clear();
                    }
                }
                //15.取消选择键SelectionKey
                it.remove();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }


   }
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值