---------------------- android培训、java培训、期待与您交流! ----------------------
应用程序可调用SelectableChannel的register方法将其注册到指定的Selector上,当Selector上某些SelectableChannel上有需要处理的IO操作是,程序可以调用Selector实例的select方法获取他们的数量,并通过selectedKeys方法返回他们对应的SelectableChannel集合,通过该集合就可以获取所有需要处理的IO操作的SelectableChannel集。先看一个示例,以增加对选择器的理解:
客户端:
有两条线程,一条获取键盘输入,并将其发送到服务器,另外一条接受服务器数据,并处理。
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.Scanner;
public class NClient {
// 定义检测SocketChannel的Selector对象
private Selector selector = null;
// 客户端SocketChannel
private SocketChannel sc = null;
//键盘读取缓冲区
ByteBuffer keyRead = null;
public void init() throws IOException {
//实例化选择器
selector = Selector.open();
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);
sc = SocketChannel.open(isa);
sc.configureBlocking(false);
// 将SocketChannel对象注册到指定Selector
sc.register(selector, SelectionKey.OP_READ);
// 启动读取服务器端数据的线程
new ClientThread().start();
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
while (scan.hasNextLine()) {
// 读取键盘输入
String line = scan.nextLine();
keyRead = ByteBuffer.wrap(line.getBytes());
sc.write(keyRead);
}
}
// 定义读取服务器数据的线程
private class ClientThread extends Thread {
public void run() {
try {
//检查与selector相关的通道是否有需要处理的IO操作,阻塞方法。
while (selector.select() > 0) {
// 遍历每个有可用IO操作Channel对应的SelectionKey
for (SelectionKey sk : selector.selectedKeys()) {
// 删除正在处理的SelectionKey
selector.selectedKeys().remove(sk);
// 如果该SelectionKey对应的Channel中有可读的数据
if (sk.isReadable()) {
SocketChannel sc = (SocketChannel) sk.channel();
ByteBuffer buff = ByteBuffer.allocate(1024);
String content = "";
while (sc.read(buff) > 0) {
buff.flip();
// buff.array()将整个缓冲区都解析为数组,下面取有内容的一部分。
content += new String(buff.array(), 0,buff.limit());
buff.clear();
}
System.out.println("聊天信息:" + content);
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new NClient().init();
}
}
服务器端:
接受客户端数据,然后将数据发送给所有客户端。
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
public class NServer {
// 用于检测所有Channel状态的Selector
private Selector selector = null;
public void init() throws IOException {
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);
server.socket().bind(isa);
server.configureBlocking(false);
// 将server注册到指定Selector对象
server.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
// 依次处理selector上的每个已选择的SelectionKey
for (SelectionKey sk : selector.selectedKeys()) {
// 从selector上的已选择Key集中删除正在处理的SelectionKey
selector.selectedKeys().remove(sk);
// 如果sk对应的通道包含客户端的连接请求
if (sk.isAcceptable()) {
// 调用accept方法接受连接,产生服务器端对应的SocketChannel
SocketChannel sc = server.accept();
// 设置采用非阻塞模式
sc.configureBlocking(false);
// 将该SocketChannel也注册到selector
sc.register(selector, SelectionKey.OP_READ);
}
// 如果sk对应的通道有数据需要读取
if (sk.isReadable()) {
// 获取该SelectionKey对应的Channel,该Channel中有可读的数据
SocketChannel sc = (SocketChannel) sk.channel();
// 定义准备执行读取数据的ByteBuffer
ByteBuffer buff = ByteBuffer.allocate(1024);
String content = "";
// 开始读取数据
try {
while (sc.read(buff) > 0) {
buff.flip();
content += new String(buff.array(), 0, buff.limit());
buff.clear();
}
// 打印从该sk对应的Channel里读取到的数据
System.out.println("=====" + content);
}
// 如果捕捉到该sk对应的Channel出现了异常,即表明该Channel
// 对应的Client出现了问题,所以从Selector中取消sk的注册
catch (IOException ex) {
// 从Selector中删除指定的SelectionKey
sk.cancel();
if (sk.channel() != null) {
sk.channel().close();
}
}
// 如果content的长度大于0,即聊天信息不为空
if (content.length() > 0) {
// 遍历该selector里注册的所有SelectKey
for (SelectionKey key : selector.keys()) {
// 获取该key对应的Channel
Channel targetChannel = key.channel();
// 如果该channel是SocketChannel对象
if (targetChannel instanceof SocketChannel) {
// 将读到的内容写入该Channel中
SocketChannel dest = (SocketChannel) targetChannel;
dest.write(ByteBuffer.wrap(content.getBytes()));
}
}
}
}
}
}
}
public static void main(String[] args) throws IOException {
new NServer().init();
}
}
以上程序是选择器的基本应用,他可以以一条线程处理多个客户端请求。后面有关于选择器的详解。
---------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima