selector 一般称 为选择器 ,它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写等,可以实现单线程管理多个channels,也就是可以管理多个网络链接。
1.阻塞式,不使用用selector,和传统BIO 一样,当有多个客户端链接时,服务端需要开启多线程,
2.非阻塞式,当有多个客户端链接时,服务器只需要开启一个线程
selector的使用案例
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 Server {
public static void main(String[] args) {
try {
ServerSocketChannel sschannel = ServerSocketChannel.open();
sschannel.bind(new InetSocketAddress(10086));
System.out.println("server is running at"+sschannel.getLocalAddress());
sschannel.configureBlocking(false);
//获取选择器
Selector selector = Selector.open();
//将通道注册到选测器,指定接受“监听事件”
sschannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select()>0){
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()){
//获取准备就绪的事件
SelectionKey sk =it.next();
//判断是什么事件就绪
if(sk.isAcceptable()){
//若是接受就绪,就获取客户端链接
SocketChannel schannel = sschannel.accept();
System.out.println("client"+schannel.getRemoteAddress()+" has connected");
schannel.configureBlocking(false);
schannel.register(selector,SelectionKey.OP_READ);
}else if(sk.isReadable()){
//获取当前选择器上“读就绪”状态的通道
SocketChannel socketChannel = (SocketChannel) sk.channel();
//读数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len =0;
while ((len = socketChannel.read(buffer))>0){
buffer.flip();
System.out.println("["+socketChannel.getRemoteAddress()+"]:"+new String(buffer.array(),0,len));
buffer.clear();
}
}
//取消选择建
it.remove();
}
}
sschannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
public class Client1 {
public static void main(String[] args) {
try {
//1.建立SocketChannel
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",10086));
//2.设置非阻塞模式
socketChannel.configureBlocking(false);
//3.分配缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//4.发送数据给服务端
Scanner scanner = new Scanner(System.in);
String str = null;
while (!"quit".equals(str)){
System.out.println("请说:");
str= scanner.nextLine();
byteBuffer.put((str+" "+printTime3(null)).getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
}
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 按格式输出当前时间
* @param pattern 时间格式,如HH:mm:ss yyyyy-MM-dd
* @return 格式化后的时间字符串
*/
public static String printTime3(@Nullable String pattern){
String pat = "yyyy-MM-dd HH:mm:ss";
if(pattern==null||"".equals(pattern)) {
pattern = pat;
}
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return formatter.format(ldt);
}
}
运行结果: