一、Nio简介
nio 是non-blocking的简称,在jdk1.4 里提供的新api 。Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持。字符集编码解码解决方案。 Channel :一个新的原始I/O 抽象。 支持锁和内存映射文件的文件访问接口。 提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O 。
java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率。在nio包中主要包括以下几个类或接口:
* Buffer:缓冲区,用来临时存放输入或输出数据。* Charset:用来把Unicode字符编码和其它字符编码互转。* Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer。* Selector:用来支持异步I/O操作,也叫非阻塞I/O操作。
nio包中主要通过下面两个方面来提高I/O操作效率:
* 通过Buffer和Channel来提高I/O操作的速度。* 通过Selector来支持非阻塞I/O操作。
传送门:
二、NioSocket
NIO为socket提供了新的连接方式。使用NioSocket的流程如下:
Created with Raphaël 2.1.0开始建立ServerSocketChannel设置相应的参数。创建Selector并注册到ServerSocketChannel上。调用Selector的select方法等待请求,可以制定超时时间。Selector接收到请求后使用selectedKeys返回SelectionKey集合。使用SelectionKey获取到Channel、Selector和操作类型并进行具体的操作。结束
三、服务器示例代码
package com.frank.java.util;/** * Created by Administrator on 2016/6/24. */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.nio.charset.Charset;import java.util.Iterator;public class NIOServer { public static void main(String[] args) throws Exception{ //创建ServerSocketChannel,监听8080端口 ServerSocketChannel ssc=ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8081)); //设置为非阻塞模式 ssc.configureBlocking(false); //为ssc注册选择器 Selector selector=Selector.open(); ssc.register(selector, SelectionKey.OP_ACCEPT); //创建处理器 Handler handler = new Handler(1024); while(true){ // 等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,如果传入0或者不传参数将一直阻塞 if(selector.select(3000)==0){ System.out.println("等待请求超时。。。"); continue; } System.out.println("处理请求。。。"); // 获取待处理的SelectionKey IteratorkeyIter=selector.selectedKeys().iterator(); while(keyIter.hasNext()){ SelectionKey key=keyIter.next(); try{ // 接收到连接请求时 if(key.isAcceptable()){ handler.handleAccept(key); } // 读数据 if(key.isReadable()){ handler.handleRead(key); } } catch(IOException ex) { keyIter.remove(); continue; } // 处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key keyIter.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 client: " + receivedString); // 返回数据给客户端 String sendString = "received data: " + receivedString; buffer = ByteBuffer.wrap(sendString.getBytes(localCharset)); sc.write(buffer); // 关闭Socket sc.close(); } } }}