NioSocket的用法
不知道该咋说(ง •_•)ง
ServerSocketChannel和SocketChannel,它们对应原来的ServerSocket和Socket。
Buffer、Channel和Selector
Buffer就是所要送的货物,Channel就是送货员(或者开往某个区域的配货车),Selector就是中转站的分拣员。
NioSocket使用中首先要创建ServerSocketChannel,然后注册Selector,接下来就可以用Selecto接收请求并处理了。
ServerSocketChannel可以使用自己的静态工厂方法open创建。每个ServerSocketChannel对应一个ServerSocket,可以调用其socket方法来获取,一般使用获取到的ServerSocket来绑定端口。ServerSocketChannel可以通过configureBlocking方法设置是否采用阻塞模式,如果要采用非阻塞模式可以用configureBlocking(false)来设置,设置了非阻塞模式之后就可以调用register方法注册Selector来使用了(阻塞模式不可以使用Selector)。
Selector可以通过其静态工厂方法open创建,创建后通过Channel的register方法注册到ServerSocketChannel或者SocketChannel上,注册完之后Selector就可以通过select方法来等待请求,select方法有一个long类型的参数,代表最长等待时间,如果在这段时间里接收到了相应操作的请求则返回可以处理的请求的数量,否则在超时后返回0,程序继续往下走,如果传入的参数为0或者调用无参数的重载方法,select方法会采用阻塞模式直到有相应操作的请求出现。当接收到请求后Selector调用selectedKeys方法返回SelectionKey的集合。
public class NIOServer {
public static void main(String[] args) throws Exception {
//创建ServerSocketChannel,监听8080端口
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(8080));//使用获取到的ServerSocket来绑定端口
//设置为非阻塞模式,阻塞模式不可以使用Selector
ssc.configureBlocking(false);
//为ssc注册选择器
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
//创建处理器
Handler handler = new Handler(1024);
while(true){
//等待请求,每次等待阻塞3秒,超过3s后线程继续向下运行,如果传入0或者不传参数将一直阻塞
if(selector.select(3000)==0){
System.out.println("等待请求超时......");
continue;
}
System.out.println("处理请求......");
//获取待处理的SelectionKey
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while(keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
try{//接收到连接请求时
//如果是接受请求操作
if(key.isAcceptable()){
handler.handleAccept(key);
}
//如果是读数据操作
if(key.isReadable()){
handler.handleRead(key);
}
//还有isConnectable,isWritable
}catch (IOException ex){
//处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key
keyIterator.remove();
continue;
}
keyIterator.remove();
}
}
}
private static class Handler{
private int bufferSize = 1024;
private String localCharset = "UTF-8";
public Handler(){}
public Handler(int bufferSize){
this(bufferSize,null);
}
public Handler(String localCharset){
this(-1,localCharset);
}
public Handler(int bufferSize, String localCharset) {
if (bufferSize > 0)
this.bufferSize = bufferSize;
if (localCharset != null)
this.localCharset = localCharset;
}
public void handleAccept(SelectionKey key) throws IOException{
SocketChannel SC = ((ServerSocketChannel)key.channel()).accept();
SC.configureBlocking(false);
SC.register(key.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
}
public void handleRead(SelectionKey key) throws IOException{
//获取channel
SocketChannel sc = (SocketChannel)key.channel();
//获取buffer并重置
ByteBuffer buffer = (ByteBuffer)key.attachment();
buffer.clear();
//没有读到内容则关闭
if(sc.read(buffer) == -1){
sc.close();
}else{
//将buffer转换为读状态
buffer.flip();
//将buffer中接收到的值按localCharset格式编码后保存到receivedString
String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
System.out.println("received from cient: "+receivedString);
//返回数据给客户端
String sendString = "received data: "+receivedString;
buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
sc.write(buffer);
//关闭Socket
sc.close();
}
}
}
}
// java.nio.Buffer
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}