NIO同步非阻塞,详细原理见代码注释。
- 服务器端代码
package niodemo.niochat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
//如下的代码就实现了服务器仅仅通过1个线程(没有创建新的线程就是主线程)监听多个客户端的请求,可以写客户端测试,也可以用telnet
public class NIOSelectorServer {
private static Charset charset = Charset.forName("unicode");
public static void main(String[] args) throws IOException {
//1. 创建ServerSocketChannel,通过open()获得channel实例
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.绑定ip
InetSocketAddress inetSocketAddress = new InetSocketAddress(6666);
serverSocketChannel.bind(inetSocketAddress);
//3. 将serverSocketChannel设置成非阻塞的
serverSocketChannel.configureBlocking(false);
//4. 创建Selector
Selector selector = Selector.open();
//5. 将ServerSocketChannel注册到Selector上:注意:首次注册都是注册到selector上的所有的SelectionKey集合上
//【Selector上注册的都是channel,在服务器端就一个channel就是ServerSocketChannel】
//注册是以事件的方式注册到selector上,serverSocketChannel这个服务器端通道关注的事件是accept
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
/*
* (1) SelectionKey类是Selector类上的集合,Selector上有3个SelectionKey,分别是:所有的SelectionKey,
* 已选择的SelectionKey,和废弃的SelectionKey。
* (2) SelectionKey上有4中事件类型(注册到selector上的channel都是通过事件注册的)分别是:
* OP_ACCEPT, OP_CONNECT, OP_READ, OP_WRITE
* (3) 其中,服务器端的通道是ServerSocektChannel就一个,关注的事件是OP_ACCEPT
* 服务器接收客户端请求的通道是SocketChannel是多个的,一个客户端一个SocketChannel,关注的事件是OP_READ和OP_WRITE
* 写客户端的时候,客户端的SocketChannel关注的事件是OP_CONNECT
* */
//6. 在selector上使用select()方法轮询所有的SelectionKey集合
System.out.println("select()自身以阻塞的方式等待客户端连接......");
while (selector.select() > 0) {
//select()的返回值大于0,说明所有的SelectionKey集合上有事件发生
//有事件发生的就将其从selector上所有的SelectionKey集合转移到已选择的SelectionKey集合上。
//7. 遍历已选择的SelectionKey集合,遍历是方法:迭代器,for循环
//需要注意的是:selector.selectedKeys()方法返回的是已选择的SelectionKey集合,当有事件发生的时候遍历的就是已选择的SelectionKey集合
//而selector.select()轮询的是所有的SelectionKey集合
Set<SelectionKey> selectionKeys = selector.