聊天室服务端
public class NIOServer {
public static void main(String[] args) {
try {
//存放所有客户端的SocketChannel,用于广播消息
List<SocketChannel> allChannel = new ArrayList<>();
//创建总机,ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//ServerSocketChannel模式为阻塞模式,可以将其设置为非阻塞模式
serverSocketChannel.configureBlocking(false);//传入false设置为非阻塞模式
//为ServerSocketChannel绑定服务端口,客户端可以通过该端口与我们建立连接
serverSocketChannel.bind(new InetSocketAddress(8088));
//以上创建为固定模式,以后都可以用这样的形式创建ServerSocketChannel的非阻塞模式
/*
多路选择器的应用
这个是NIO解决非阻塞的关键API,用于监听所有通道对应的事件,并做出对应的操作。
我们的线程只要轮询处理多路选择器中待处理的通道事件即可完成所有通道的工作,
避免使用大量线程
处于阻塞来减少不必要的系统开销。
*/
Selector selector = Selector.open();//使用其静态方法open获取一个多路选择器实例
/**
* 让"总机"ServerSocketChannel向多路选择器上注册一个事件,即:accept事件。
* 原因:原来使用ServerSocket时,一旦主线程调用accept方法就会进入阻塞状态,
直到一个客户端连接
* 否则将无法继续执行其他工作。而现在的操作是让多路选择器关心该事件,
避免让线程处于阻塞。
*/
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
/*
多路选择器的select方法
当注册在该选择器上的channel有事件待处理时,此方法会立即返回一个int值,
表示有多少个事件待处理
若没有任何事件待处理时,此方法会形成阻塞。
*/
System.out.println("等待选择器告知是否有事件等待处理...");
selector.select();
System.out.println("选择器有事件待处理!!!");
//通过选择器获取所有待处理的事件
Set<SelectionKey> ketSet = selector.selectedKeys();
for (SelectionKey key : ketSet) {
//判断该事件是否为可以接受一个客户端连接了(对应的是
向多路选择器注册的事件SelectionKey.OP_ACCEPT)
if (key.isAcceptable()) {
//处理接收客户端连接的操作
/*
通过SelectionKey的方法channel()获取该事件触发的通道
因为只有ServerSocketChannel向多路选择器注册了OP_ACCEPT事件,
因此当该事件
isAcceptable()返回值为true,则说明该事件一定是由
ServerSocketChannel触发的
所以我们通过该事件获取触发该事件的通道时,一定获取的是
ServerSocketChannel
*/
ServerSocketChannel channel =
(ServerSocketChannel) = key.channel();
/*
获取的SocketChannel与原来ServerSocket.accept返回的
Socket道理一致
通过该SocketChannel就可以与连接的客户端进行双向交互数据了
*/
SocketChannel socket = channel.accept();//接受客户端的连接
/*
非阻塞的ServerSocketChannel就算多路选择器提示有客户端请求