共计 3803 个字符,预计需要花费 10 分钟才能阅读完成。
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();} | |
} | |
} |
正文完