一、概念(io\nio)
Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。IO是面向流的,NIO是面向缓冲区的。
nio特性:
1 为所有原始类型提供给缓存支持
2 提供一个新的管道 chanel
3 支持锁和内存映射文件的访问接口
4 多路复用(linux就是用的这个模型)
二 、阻塞与非阻塞
阻塞:传统io的各种流都是阻塞的。
阻塞点:1 Socket等待客户端连接
2 读取流中数据
这样线程就会被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。开启多线程的话,为每一个请求开启一个线程,这种方法如果流量多,那么就浪费系统资源。
非阻塞:也是有组赛点的 this.selector.select();,但是读写数据的时候是没有阻塞点的。
阻塞io基于socket的嘛,我们就先不说,下面是nio的简单实现,代码如下:
public class ServerNIO {
private Selector selector;//注册选择器
private String uri;
private String agreement;//协议
public static void main(String[] args) {
ServerNIO server= new ServerNIO();
try {
server.initServer(7001);
server.ListenSelector();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void initServer(int port) throws Exception {
//服务端开启
ServerSocketChannel serverChannel = ServerSocketChannel.open();
//阻塞改为false
serverChannel.configureBlocking(false);
//绑定端口
serverChannel.socket().bind(new InetSocketAddress(port));
this.selector = Selector.open();
//为选择器注册监听事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务端已开启。。。");
}
public void ListenSelector() throws Exception{
//轮询监听selector
while(true) {
this.selector.select();
Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
if(iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
//有效key
if(selectionKey.isValid()) {
//处理当前请求
handler(selectionKey);
}
}
}
}
/**
* <p>处理客户端请求</p>
* @param selectionKey
* @throws IOException
*/
private void handler(SelectionKey key) throws IOException {
//判断是什么类型的请求 连接请求
if(key.isAcceptable()) {
ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel();
SocketChannel socketChannel = serverChannel.accept();
socketChannel.configureBlocking(false);
//设置读超时
socketChannel.socket().setSoTimeout(5000);
//如果接收到连接请求后,需要给请求注册读权限
socketChannel.register(selector, SelectionKey.OP_READ);
}
//读请求
if(key.isReadable()) {
SocketChannel socketChannel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
if((socketChannel.read(buffer))>0) {
String msg = new String(buffer.array());
HttpRequestNIO request= new HttpRequestNIO(msg);
uri = request.getUri();
agreement = request.getAgreement().trim();
if(isStatic(uri)) {
socketChannel.register(selector, SelectionKey.OP_WRITE);
System.out.println("此处返回静态文件");
}else {
System.out.println("此处返回动态文件");
}
}else {
System.out.println("客户端关闭");
key.cancel();
return;
}
}
if(key.isWritable()) {
SocketChannel socketChannel = (SocketChannel)key.channel();
HttpResponseNIO Response = new HttpResponseNIO(socketChannel);
Response.wirte(uri);
Response.wirteAgreement(agreement);
}
}
private static Boolean isStatic(String uri) {
Boolean isStatic = false;
String[] suffix = {".html",".css",".png",".jpeg",".js",".ico"};
for (String string : suffix) {
if(uri.endsWith(string)) {
isStatic = true;
}
}
return isStatic;
}
}