Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。
Java NIO: Channels and Buffers(通道和缓冲区)
标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
Java NIO: Non-blocking IO(非阻塞IO)
Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
Java NIO: Selectors(选择器)
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
package com.xxx.xxxController;
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;
import java.util.Set;
public class NioServer {
private Selector selector;
public void initServer(String adrress, int port) throws IOException {
//1:建立一个Socket连接通道
ServerSocketChannel nioSocketChannel = ServerSocketChannel.open();
//2: 将连接设置成非阻塞
nioSocketChannel.configureBlocking(false);
//3: 绑定socket监听地址
nioSocketChannel.socket().bind(new InetSocketAddress(adrress, port));
//4: 获取通道管理器
this.selector = Selector.open();
//5: 将通道与管理器绑定, 并注册SelectionKey.OP_ACCEPT事件
nioSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
}
public void listen() throws IOException {
System.out.println("server started");
while (true) {
//监听客户端事件,阻塞
selector.select();
Set<SelectionKey> keySet = selector.selectedKeys();
//处理客户端连接和请求
Iterator<SelectionKey> it = keySet.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
handler(key);
}
}
}
public void handler(SelectionKey key) throws IOException {
if(key.isAcceptable()) {
handlerAccept(key);
} else if(key.isReadable()) {
handlerRead(key);
}
}
public void handlerAccept(SelectionKey key) throws IOException {
//获取Key上绑定的通道
ServerSocketChannel nioSocketChannel = (ServerSocketChannel) key.channel();
//监听连接并返回连接的通道,非阻塞通道直接返回
SocketChannel acceptChannel = nioSocketChannel.accept();
acceptChannel.configureBlocking(false);
System.out.println("new client accepted");
//将通道与管理器绑定, 并注册SelectionKey.OP_事件
acceptChannel.register(this.selector, SelectionKey.OP_READ);
}
public void handlerRead(SelectionKey key) throws IOException {
SocketChannel readChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = readChannel.read(buffer);
if(read > 0) {
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("clent sent msg :" + msg);
ByteBuffer outBuffer = ByteBuffer.wrap("msg confirmed!".getBytes());
readChannel.write(outBuffer);
} else {
System.out.println("客户端关闭");
key.cancel();
}
}
public static void main(String[] args){
NioServer nioServer = new NioServer();
try {
nioServer.initServer("127.0.0.1", 8888);
nioServer.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用telnet客户端 telnet 127.0.0.1 8888 输出结果: server started new client accepted clent sent msg :s clent sent msg :d clent sent msg :m clent sent msg :q 客户端关闭