Java的NIO模式的Selector网络通讯,其实就是一个简单的Reactor模型。
下面是一个典型的NIO Reactor模型原型实现。
package com.lands.nio;
import java.io.IOException;
import java.net.InetAddress;
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;
public class SimpleServer {
public static void testServer() throws IOException {
// 创建Selector选择器
Selector selector = Selector.open();
// 创建服务端通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 服务端通道设置为非阻塞
serverSocketChannel.configureBlocking(false);
// 服务端通道绑定服务端口
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), 7777));
// 将选择器和ACCEPT事件注册到服务端通道上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 采用阻塞式轮询的方式,监听获取服务端通道上注册的事件
while (selector.select() > 0) {
// 获取当前选择器监听到的所有事件KEY
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
// 逐一识别事件KEY
SelectionKey selectedKey = selectedKeys.next();
// 是否为ACCEPT事件(连接就绪事件)
if (selectedKey.isAcceptable()) {
// 建立客户端通道连接
SocketChannel socketChannel = serverSocketChannel.accept();
// 切换为非阻塞模式
socketChannel.configureBlocking(false);
// 为客户端通道注册选择器和READ事件(读就绪事件)
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectedKey.isReadable()) {
// 如果是READ事件(读就绪事件),获取该选择器上的“读就绪”状态的客户端通道
SocketChannel socketChannel = (SocketChannel) selectedKey.channel();
// 读取数据,建立缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = socketChannel.read(byteBuffer)) != -1) {
//确定当前缓冲区的有效数据,为数据输出做准备。flip缓冲区回针操作。
byteBuffer.flip();
//输出缓冲区中的数据
System.out.println(new String(byteBuffer.array(), 0, length));
//复位缓冲区的所有标志位,为下一次Readable事件做准备
byteBuffer.clear();
}
socketChannel.close();
}
//移除所有选择键
selectedKeys.remove();
}
} // while (selector.select() > 0)
//关闭连接
serverSocketChannel.close();
}
public static void main(String[] args) throws IOException {
testServer();
}
}
package com.lands.nio;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
// 1.创建客户端Socket,指定服务器地址和端口
Socket so = new Socket(InetAddress.getLocalHost(), 7777);// 端口号要和服务器端相同
// 2.获取输出流,向服务器端发送登录的信息
OutputStream os = so.getOutputStream();// 字节输出流
PrintWriter pw = new PrintWriter(os);// 字符输出流
BufferedWriter bw = new BufferedWriter(pw);// 加上缓冲流
bw.write("用户名:admin;密码:123");
bw.flush();
so.shutdownOutput();// 关闭输出流
// 3.关闭资源
bw.close();
pw.close();
os.close();
so.close();
}
}
实际上的Reactor模式,是基于Java NIO的,在他的基础上,抽象出来两个组件——Reactor和Handler两个组件:
(1)Reactor:负责响应IO事件,当检测到一个新的事件,将其发送给相应的Handler去处理;新的事件包含连接建立就绪、读就绪、写就绪等。
(2)Handler:将自身(handler)与事件绑定,负责事件的处理,完成channel的读入,完成处理业务逻辑后,负责将结果写出channel。