package dock;
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;
import java.util.Set;
//学习网址
//http://ifeve.com/selectors/ 浪迹v
//https://www.cnblogs.com/f1194361820/p/4019575.html FangJinuo
//http://blog.csdn.net/canot/article/details/51372651 不能说的秘密go
//https://www.cnblogs.com/Theshy/p/7696313.html 不愿做一个代码机器的程序员
public class SocketNio {
public static void main(String[] args) {
try {
SocketNio nio = new SocketNio();
nio.init();
} catch (IOException e) {
System.out.println(e.toString());
}
}
public void init() throws IOException {
//Charset charset = Charset.forName("GBK");
// 创建一个选择器,可用close()关闭,isOpen()表示是否处于打开状态,他不隶属于当前线程
//AbstractSelector selector = SelectorProvider.provider().openSelector();
Selector selector = Selector.open();
// 创建ServerSocketChannel,并把它绑定到指定端口上
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(7777), 1024);
// 设置为非阻塞模式, 这个非常重要
server.configureBlocking(false);
// 在选择器里面注册关注这个服务器套接字通道的accept事件
// ServerSocketChannel只有OP_ACCEPT可用,OP_CONNECT,OP_READ,OP_WRITE用于SocketChannel
server.register(selector, SelectionKey.OP_ACCEPT);
while (true){
selector.select(1000);
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
SelectionKey key = null;
while (it.hasNext()){
// 如果key对应的Channel包含客户端的链接请求
// OP_ACCEPT 这个只有ServerSocketChannel才有可能触发
key = it.next();
//由于select操作只管对selectedKeys进行添加,所以key处理后我们需要从里面把key去掉
it.remove();
if (key.isAcceptable()){
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
// 得到与客户端的套接字通道
SocketChannel channel = ssc.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
// 将key对应Channel设置为准备接受其他请求
key.interestOps(SelectionKey.OP_ACCEPT);
}
if (key.isReadable()){
key.interestOps(SelectionKey.OP_WRITE);
//new Thread(new Task(key)){}.start();
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
String content = "";
try {
int readBytes = channel.read(byteBuffer);
if (readBytes > 0) {
byteBuffer.flip(); // 为write()准备
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
content += new String(bytes);
System.out.println(content);
// 回应客户端
doWrite(channel);
}
// 写完就把状态关注去掉,否则会一直触发写事件(改变自身关注事件)
//key.interestOps(SelectionKey.OP_READ);
} catch (IOException i) {
// 如果捕获到该SelectionKey对应的Channel时出现了异常,即表明该Channel对于的Client出现了问题
// 所以从Selector中取消该SelectionKey的注册
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}
}
}
}
}
//
private void doWrite(SocketChannel sc) throws IOException {
byte[] req = "服务器已接受\r\n".getBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(req.length);
byteBuffer.put(req);
byteBuffer.flip();
sc.write(byteBuffer);
if (!byteBuffer.hasRemaining()) {
System.out.println("Send 2 Service successed");
}
sc.close();
}
//读事件注释留底
/* SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
String content = "";
try {
int readBytes = channel.read(byteBuffer);
if (readBytes > 0) {
byteBuffer.flip(); // 为write()准备
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
content += new String(bytes);
System.out.println(content);
// 回应客户端
doWrite(channel);
}
// 写完就把状态关注去掉,否则会一直触发写事件(改变自身关注事件)
//key.interestOps(SelectionKey.OP_READ);
} catch (IOException i) {
// 如果捕获到该SelectionKey对应的Channel时出现了异常,即表明该Channel对于的Client出现了问题
// 所以从Selector中取消该SelectionKey的注册
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}*/
}