目标
1.理解什么是NIO,优劣情况等...
2.其实想补充一点自己的理解,但是怕写出来误导人,这里就暂时不'扯'了...
参考博文
1.https://www.cnblogs.com/barrywxx/p/8430790.html
2.https://blog.youkuaiyun.com/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();
}
}
}