selector 模型
应用一个线程去监控多个 IO 申请,如果哪一个 IO 数据筹备结束后就告诉相应的线程来解决
select 模型,它的基本原理是采纳轮询和遍历的形式。也就是说,在客户端操作服务器时,会创立三种文件描述符,简称 FD。别离是 writefds(写描述符)、readfds(读描述符)和 exceptfds(异样描述符)
demo,让主线程监听 IO 事件而后进行解决
server
public class NioServerExample {public static void main(String[] args) throws IOException {Selector selector = getSelector();
listen(selector);
}
public static Selector getSelector() throws IOException {Selector selector = Selector.open();
// 创立可选通道,设置非阻塞
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
// 绑定通道到指定端口
ServerSocket socket = serverSocketChannel.socket();
socket.bind(new InetSocketAddress(8080));
// 向 selector 注册 IO 事件, 首先注册 SelectionKey.OP_ACCEPT 让 server accept 监听
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
return selector;
}
public static void listen(Selector selector) throws IOException {while (selector.select() > 0) {Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
if (iterator.hasNext()) {SelectionKey key = iterator.next();
iterator.remove();
// 判断 IO 事件类型进行解决
process(selector, key);
}
}
}
private static void process(Selector selector, SelectionKey key) throws IOException {if (key.isAcceptable()) {System.out.println("事件类型 accept");
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = server.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {System.out.println("事件类型 read");
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(500);
int len = channel.read(byteBuffer);
if (len > 0) {System.out.println(new String(byteBuffer.array(), 0, len));
channel.register(selector, SelectionKey.OP_WRITE);
} else {channel.close();
}
byteBuffer.clear();} else if (key.isWritable()) {System.out.println("事件类型 write");
SocketChannel channel = (SocketChannel) key.channel();
String str = "client fuck you I am Nio Server";
channel.write(ByteBuffer.wrap(str.getBytes()));
channel.close(); // 向客户端发送数据后断开此通道连贯}
}
}
client
package org.example.io.branch.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioClientExample {public static void main(String[] args) throws IOException, InterruptedException {Selector selector = getSelector();
listen(selector);
}
private static Selector getSelector() throws IOException {Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_WRITE);
return selector;
}
private static void listen(Selector selector) throws IOException {while (selector.select() > 0) {Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
if (iterator.hasNext()) {SelectionKey key = iterator.next();
iterator.remove();
process(selector, key);
}
}
}
private static void process(Selector selector, SelectionKey key) throws IOException {if (key.isWritable()) {SocketChannel channel = (SocketChannel) key.channel();
channel.configureBlocking(false);
String info = "fuck you server I am Nio client";
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
byteBuffer.put(info.getBytes());
byteBuffer.flip();
channel.write(byteBuffer);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
int len = channel.read(byteBuffer);
if (len > 0) {System.out.println(new String(byteBuffer.array(), 0, len));
channel.register(selector, SelectionKey.OP_WRITE);
} else {channel.close();
}
byteBuffer.clear();}
}
}