java的nio为非阻塞式socket通信提供了如下几个类:
Selector : 它是SelectableChannel对象的多路复用器,所有希望采用非阻塞方式进行通信的channel都应该注册到Selector对象。可以通过调用此类的open()静态方法来创Selector实例,该方法将使用系统默认的Selector来返回新的Selector。
Selector可以同时监控多个SelectortableChannel的IO状况,是非阻塞IO的核心。一个Selector实例有3个SelectIonKey集合
1.所有的SelectionKey集合:代表了注册在该Selector上的Channel,该集合可以通过keys()方法返回。
2.被选择的SelectionKey集合 : 代表了所有可通过select()方法获取的,需要进行IO处理的Channel,这个集合可以通过selectedKeys()返回。
3.被取消的SelectionKey集合:代表了所有被取消注册关系的Channel,在下一次执行select()方法时,这些Channel对应的SelectionKey会被彻底删除,程序通常无须直接访问该集合。
Selector还提供了一系列和select()相关的方法。
int select() : 监控所有注册的Channel,当它们中间有需要处理的IO操作时,该方法返回,并将对应的Selection加入被选择的SelectionKey集合中,该方法返回这些Channel的数量。
int select(long timeout) : 可以设置超时时长的select()操作
int selectNow() : 执行一个立即返回的select()操作,相对于无参数的select()方法而言,该方法不会阻塞线程。
Selector wakeup() : 使一个还未返回的select()方法立刻返回
SelectableChannel类提供了如下方法来设置和返回该channel的模式状态
SelectableChannel configureBlocking(boolean block) : 设置是否采用阻塞模式
boolean isBlocking() : 返回该channel是否是阻塞模式
int vaildOPs() : 返回一个整数值,表示这个Channel所支持的IO操作 OP_READ(1), OP_WRITE(4),OP_CONNECT(8),OP_ACCEPT(16)
SelectableChannel还提供了如下几个方法来获取它的注册状态
boolean isRegistered() : 返回该channel是否注册在一个或多个selector上
SelectionKey keyFor(Selector sel) : 返回该channel和sel Selector之间的注册关系,如果不存在注册关系,则返回null.
就像这个图,服务器上的所有channel都需要向Selector注册,Selector则负责监视这些socket的IO状态,当其中任意一个或者多个channel具有可用的IO操作,该Selector的select()方法将会返回大于0的整数,该整数表示该Selector上有多少个channel具有可用的IO操作,并提供了selectedKeys()方法来返回这些channel对应的SelectionKey集合。正是通过Selector,使得服务器端只需要不断的调用Selector实例的select()方法,即可知道当前的所有channel是否有需要处理的IO操作。当Selector上注册的所有channel都没有需要处理的IO操作时,select()方法将会被阻塞,调用该方法的线程被阻塞
服务器端的需要使用ServerSocketChannel来对客户端进行监听部分代码如下
如果需要使用非阻塞方式来处理该ServerSocketChannel,还应该设置它的非阻塞方式,并将其注册到指定的Selector,代码片段如下