目標
1.理解什麼是NIO,優劣情況等...
2.其實想補充一點自己的理解,但是怕寫出來誤導人,這裏就暫時不'扯'了...
參考博文
1.https://www.cnblogs.com/barrywxx/p/8430790.html
2.https://blog.csdn.net/knight_black_bob/article/details/88223838
核心代碼
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 tomcat.base.TomcatModule;
public class NIOModule implements TomcatModule,Runnable{
// 多路複選器
private Selector selector;
// 緩衝區
private ByteBuffer writeBuf = ByteBuffer.allocate(1024);
private ByteBuffer readBuf = ByteBuffer.allocate(1024);
@Override
public void createLink() {
new Thread(this).start();
}
@Override
public void run() {
try {
this.initSelector();
this.doSomething();
}catch(Exception e) {
e.printStackTrace();
}
}
/**
* 1 打開多路複用器
* 2 打開服務器通道
* 3 設置服務器通道爲非阻塞模式
* 4 綁定地址
* 5 把服務器通道註冊到多路複用器上,並且監聽阻塞事件
* @param 參數
* @date 2019年8月19日 下午3:54:52
* @return void
* @throws
*/
private void initSelector() {
try {
this.selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.bind(new InetSocketAddress(8888));
ssc.register(this.selector, SelectionKey.OP_ACCEPT);
}catch(Exception e) {
e.printStackTrace();
}
}
private void doSomething() {
try {
while(true) {
this.selector.select();
Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
while(keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if(key.isValid()) {
if(key.isAcceptable()) { // 判斷爲阻塞狀態
this.accept(key);
} else if(key.isReadable()) { // 判斷爲讀取狀態
this.read(key);
this.write(key);
}
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
private void write(SelectionKey key){
try {
SocketChannel sc = (SocketChannel) key.channel();
sc.register(this.selector, SelectionKey.OP_WRITE);
this.writeBuf.clear();
this.writeBuf.put("sixogd".getBytes("UTF-8"));
this.writeBuf.flip();
sc.write(this.writeBuf);
this.writeBuf.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null!=key)key.cancel();
}
}
private void read(SelectionKey key) {
try {
//1 清空緩衝區舊的數據
this.readBuf.clear();
//2 獲取之前註冊的socket通道對象
SocketChannel sc = (SocketChannel) key.channel();
//3 讀取數據
int count = sc.read(this.readBuf);
//4 如果沒有數據
if(count != -1){
//5 有數據則進行讀取 讀取之前需要進行復位方法(把position 和limit進行復位)
this.readBuf.flip();
//6 根據緩衝區的數據長度創建相應大小的byte數組,接收緩衝區的數據
byte[] bytes = new byte[this.readBuf.remaining()];
//7 接收緩衝區數據
this.readBuf.get(bytes);
//8 打印結果
String body = new String(bytes).trim();
System.out.println("Server : " + body);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 1 獲取服務通道
* 2 執行阻塞方法
* 3 設置阻塞模式
* 4 註冊到多路複用器上,並設置讀取標識
* @param @param key 參數
* @date 2019年8月19日 下午4:03:10
* @return void
* @throws
*/
private void accept(SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(this.selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
}
}