陆小曼|Java IO,讲的实在是太好了,这篇(11)


channel:该选择键绑定的通道selector:轮询到该选择键的选择器readyOps:当前就绪选择键的值interesOps:该选择器对该通道感兴趣的所有选择键选择键的作用是:在选择器轮询到有就绪通道时 , 会返回这些通道的就绪选择键(SelectionKey) , 通过选择键可以获取到通道进行操作 。
简单了解了选择器后 , 我们可以结合缓冲区、通道和选择器来完成一个简易的聊天室应用 。
示例:简易的客户端服务器通信先说明 , 这里的代码非常的臭和长 , 不推荐细看 , 直接看注释附近的代码即可 。
我们在服务器端会开辟两个线程
Thread1:专门监听客户端的连接 , 并把通道注册到客户端选择器上Thread2:专门监听客户端的其它IO状态(读状态) , 当客户端的IO状态就绪时 , 该选择器会轮询发现 , 并作相应处理publicclassNIOServer{SelectorserverSelector=Selector.open();SelectorclientSelector=Selector.open();publicstaticvoidmain(String[]args)throwsIOException{NIOServerserver=nweNIOServer();newThread(()->{try{//对应IO编程中服务端启动ServerSocketChannellistenerChannel=ServerSocketChannel.open();listenerChannel.socket().bind(newInetSocketAddress(3333));listenerChannel.configureBlocking(false);listenerChannel.register(serverSelector,SelectionKey.OP_ACCEPT);server.acceptListener();}catch(IOExceptionignored){}}).start();newThread(()->{try{server.clientListener();}catch(IOExceptionignored){}}).start();}}//监听客户端连接publicvoidacceptListener(){while(true){if(serverSelector.select(1)>0){Setset=serverSelector.selectedKeys();IteratorkeyIterator=set.iterator();while(keyIterator.hasNext()){SelectionKeykey=keyIterator.next();if(key.isAcceptable()){try{//(1)每来一个新连接 , 注册到clientSelectorSocketChannelclientChannel=((ServerSocketChannel)key.channel()).accept();clientChannel.configureBlocking(false);clientChannel.register(clientSelector,SelectionKey.OP_READ);}finally{//从就绪的列表中移除这个keykeyIterator.remove();}}}}}}//监听客户端的IO状态就绪publicvoidclientListener(){while(true){//批量轮询是否有哪些连接有数据可读if(clientSelector.select(1)>0){Setset=clientSelector.selectedKeys();IteratorkeyIterator=set.iterator();while(keyIterator.hasNext()){SelectionKeykey=keyIterator.next();//判断该通道是否读就绪状态if(key.isReadable()){try{//获取客户端通道读入数据SocketChannelclientChannel=(SocketChannel)key.channel();ByteBufferbyteBuffer=ByteBuffer.allocate(1024);clientChannel.read(byteBuffer);byteBuffer.flip();System.out.println(LocalDateTime.now().toString()+"Server端接收到来自Client端的消息:"+Charset.defaultCharset().decode(byteBuffer).toString());}finally{//从就绪的列表中移除这个keykeyIterator.remove();key.interestOps(SelectionKey.OP_READ);}}}}}}在客户端 , 我们可以简单的输入一些文字 , 发送给服务器
publicclassNIOClient{publicstaticfinalintCAPACITY=1024;publicstaticvoidmain(String[]args)throwsException{ByteBufferdsts=ByteBuffer.allocate(CAPACITY);SocketChannelsocketChannel=SocketChannel.open(newInetSocketAddress("127.0.0.1",3333));socketChannel.configureBlocking(false);Scannersc=newScanner(System.in);while(true){Stringmsg=sc.next();dsts.put(msg.getBytes());dsts.flip();socketChannel.write(dsts);dsts.clear();}}}下图可以看见 , 在客户端给服务器端发送信息 , 服务器接收到消息后 , 可以将该条消息分发给其它客户端 , 就可以实现一个简单的群聊系统 , 我们还可以给这些客户端贴上标签例如用户姓名 , 聊天等级······ , 就可以标识每个客户端啦 。 在这里由于篇幅原因 , 我没有写出所有功能 , 因为使用原生的NIO实在是不太便捷 。