服务端思路:
定义一个 Charset 字符集用于解析数据
定义两个 ByteBuffered 缓冲区用于收发数据
定义一个 Map 用于存放客户端集合
定义一个 Selector 用于监听通道事件
通过 ServerSocketChannel 的 open 方法打开一个 ServerSocketChannel 通道
设置为非阻塞模式,并传递一个 InetSocketAddress 绑定端口
注册 ServerSocketChannel 的接收就绪事件通道到 Selector
循环监听事件
调用 Selector 的 select 方法阻塞直到有准备就绪的通道
调用 Selector 的 selectedKeys 获取准备就绪的通道集合
针对事件处理通道
接收就绪:
代表有客户端要连接,通过 SelectionKey 对象获取 ServerSocketChannel
调用 accept 方法接收请求客户端通道 SocketChannel
为 SocketChannel 通道注册可读数据事件到 Selector
将客户端 SocketChannel 添加到客户端集合 map 中
可读就绪:
代表客户端向服务器端发送了消息,通过 SelectionKey 对象获取 SocketChannel
调用 read 方法将数据读入通道,通过 Charset 的 decode 将数据解码
调用 dispatch 方法将消息转发给各个客户端
dispach方法:遍历客户端集合 map,通过 Channel 的 write 方法将消息发送给各个客户端
处理完事件后要清空 SelectionKey 集合,当下次该通道变成就绪时,Selector 才会再次将其放入 SelectionKey 中
public class NIOServer {
private int port = 8888;
// 用于字符集编解码
private Charset charset = Charset.forName("UTF-8");
// 用于接收数据的缓冲区
private ByteBuffer rBuffer = ByteBuffer.allocate(1024);
// 用于发送数据的缓冲区
private ByteBuffer sBuffer = ByteBuffer.allocate(1024);
// 用于存放客户端SocketChannel集合
private Map clientMap = new HashMap();
// 用于监听通道事件
private static Selector selector;
public NIOServer(int port) {
this.port = port;
try {
init();
} catch (IOException e) {
e.printStackTrace();
}<