一、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操作。
傳送門:NIO與IO的區別
二、NioSocket
NIO爲socket提供了新的連接方式。使用NioSocket的流程如下:
三、服務器示例代碼
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
Iterator<SelectionKey> keyIter=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();
}
}
}
}