java NIO之选择器学习笔记

选择器:

选择器解决的问题:选择器类管理着一个被注册的通道集合的信息和他们的就绪状态。通道和选择器一起被注册,并且使用选择器来更新通道的就绪状态。

可选择通道(SelectableChannel),这个抽象类提供了通道的可选择性所需要的公共方法。FileChannel对象不是可选择的,因为他们没有继承selectableChannel.所有socket通道都是可选择的,包括从管道(Pipe)对象中获取的通道,SelectableChannel可以被注册到selector对象上,一个通道可以被注册到多个选择器上,但是对每个选择器而言只能被注册一次。

选择键(selectionKey

选择键封装了通道与选择器的注册关系。选择键对象被SelectableChannel.register返回并提供一个表示这种注册关系的标记。通道在被注册到一个选择器上之前,必须先设置为非阻塞模式(通过调用configureBlockingfalse))。

 

调用可选择通道的register()方法会将他注册到一个选择器上。如果试图注册一个处于阻塞模式的通道,register()将抛出未检查的IlllegalBlockingModeException异常。此外,通道一旦被注册,就不能回到阻塞状态。试图这样做,则在调用configureBlocking()方法是抛出IlllegalBlockingModeException异常。并且试图注册一个已经关闭的selectablechannel实例的话,也将抛出异常(losedchannelException.

 

键的interest(感兴趣的操作)集合和ready(已经准备好的操作)集合是和特定的通道相关的,每个通道的实现,将定义他自己的选择键类。在register()方法中可以构造它并且将他传递给所提供的选择器对象。

 

使用非阻塞I/O编写服务器处理程序,大致步骤为:

1、向selector对象注册感兴趣的事件;

2、从selector中获取感兴趣的事件。

3、根据不同的事件进行相应的处理。

以下代码建立监控三个socket通道的选择器:

Selector selector=Selector.Open();

Channel1.registerselectorSelectionKey.OP_READ);

Channel2.register(selector,Selectionkey.OP_WRITE);

Channel3.register(selector,Selectionkey.OP_WRITE|OP_READ);

 

readCount =selector.select(10000);

Select方法是阻塞方法,直到过了十秒或者至少有一个通道的I/O操作准备好了。

 

SelectionKey中用静态常量定义了四中I/O操作:OP_READ 1OP_WRITE4、OP_CONNECT 8OP_ACCEPT 16.任意相加都不相同,可以通过validOps()方法返回值确定SelectableChannel支持的操作。当通道关闭时,所有相关的建会自动取消,当选择器关闭时,所有被注册到该选择器的通道都将被注销,并且相关的键将立即被无效化。一旦键无效化,调用相关的方法将抛出CancelledKeyException异常。

服务端package it.com.Jerome;

 

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.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

 

public class SelectorServer {

private Selector selector;

private ServerSocketChannel serverChannel=null;

private int keys =0;

public  void start() {

       try{

        SelectorServer ss=new SelectorServer();

        ss.initServer();

        ss.listen();

       }catch(Exception e){

        e.printStackTrace();

       }

}

public void initServer() throws IOException {

this.selector=Selector.open();

serverChannel =ServerSocketChannel.open();

serverChannel.socket().bind(new InetSocketAddress("127.0.0.1",8888));

serverChannel.configureBlocking(false);

SelectionKey key = serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);

}

public  void listen() throws Exception {

System.out.println("服务已经成功启动!");

while(true){

keys=this.selector.select();

Iterator it=this.selector.selectedKeys().iterator();

if(keys>0){

while(it.hasNext()){

SelectionKey key =(SelectionKey)it.next();

it.remove();

if(key.isAcceptable()){

serverChannel = (ServerSocketChannel)key.channel();

//和客户端链接的通道

SocketChannel channel = serverChannel.accept();

channel.configureBlocking(false);

channel.write(ByteBuffer.wrap(new String("hello client").getBytes()));

channel.register(this.selector, SelectionKey.OP_READ);

}else if(key.isReadable()){

read(key);

}

}

}

else{

System.out.println("selector finished without any keys");

}

}

}

private void read(SelectionKey key) throws IOException {

SocketChannel channel = (SocketChannel)key.channel();

ByteBuffer buff=ByteBuffer.allocate(1024);

int len=channel.read(buff);

String msg = "服务器收到的信息为:"+new String(buff.array(),0,len);

System.out.println(msg);

}

public static  void main(String args[]){

  new SelectorServer().start();

  }

}

 

客户端:package it.com.Jerome;

 

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;

public class SelectorClient {

 private Selector selector;

 private ByteBuffer outBuff = ByteBuffer.allocate(1024);

 private ByteBuffer inBuff = ByteBuffer.allocate(1024);

 private int keys=0;

 private SocketChannel channel=null;

 

 public void initClient() throws Exception{

 channel = SocketChannel.open();

 selector=selector.open();

 channel.configureBlocking(false);

 channel.connect(new InetSocketAddress("127.0.0.1",8888));

 channel.register(this.selector, SelectionKey.OP_CONNECT);

 }

public void listen() throws Exception{

while(true){

keys =this.selector.select();

if(keys>0){

Iterator it = this.selector.selectedKeys().iterator();

while(it.hasNext()){

SelectionKey key=(SelectionKey)it.next();

if(key.isConnectable()){

SocketChannel channel=(SocketChannel)key.channel();

if(channel.isConnectionPending()){

channel.finishConnect();

System.out.println("完成链接!");

}

channel.register(this.selector, SelectionKey.OP_WRITE);

}else if(key.isWritable()){

SocketChannel channel=(SocketChannel)key.channel();

outBuff.clear();

System.out.println("客户端正在写数据!");

channel.write(outBuff.wrap("我是clientA".getBytes()));

channel.register(this.selector, SelectionKey.OP_READ);

System.out.println("客户端数据写完成!");

}else if(key.isReadable()){

SocketChannel channel=(SocketChannel)key.channel();

inBuff.clear();

channel.read(inBuff);

System.out.println("==>"+new String(inBuff.array()));

System.out.println("client finish read data!");

}

}

}else{

System.out.println("没有找到感兴趣的事件!");

}

}

}

public static void main(String[] args) {

new SelectorClient().start();

       

}

public void start() {

try{

initClient();

listen();

}catch(Exception e){

e.printStackTrace();

}

}

 

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值