package org.voovan.network.nio; import org.voovan.network.EventTrigger; import org.voovan.network.MessageLoader; import org.voovan.network.SocketContext; import org.voovan.tools.ByteBufferChannel; import org.voovan.tools.TByteBuffer; import org.voovan.tools.TObject; import org.voovan.tools.log.Logger; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; /** * 事件监听器 * * @author helyho * * Voovan Framework. * WebSite: https://github.com/helyho/Voovan * Licence: Apache v2 License */ public class NioSelector { private Selector selector; private SocketContext socketContext; private ByteBufferChannel netByteBufferChannel; private ByteBufferChannel appByteBufferChannel; private NioSession session; /** * 事件监听器构造 * @param selector 对象Selector * @param socketContext socketContext 对象 */ public NioSelector(Selector selector, SocketContext socketContext) { this.selector = selector; this.socketContext = socketContext; if (socketContext instanceof NioSocket){ this.session = ((NioSocket)socketContext).getSession(); this.appByteBufferChannel = session.getByteBufferChannel(); netByteBufferChannel = new ByteBufferChannel(session.socketContext().getBufferSize()); } } /** * 所有的事件均在这里触发 */ public void eventChose() { //读取用的缓冲区 ByteBuffer readTempBuffer = ByteBuffer.allocateDirect(socketContext.getBufferSize()); if (socketContext instanceof NioSocket) { // 连接完成onConnect事件触发 EventTrigger.fireConnectThread(session); } // 事件循环 try { while (socketContext != null && socketContext.isConnected()) { if (selector.select(1000) > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> selectionKeyIterator = selectionKeys .iterator(); while (selectionKeyIterator.hasNext()) { SelectionKey selectionKey = selectionKeyIterator.next(); if (selectionKey.isValid()) { // 获取 socket 通道 SocketChannel socketChannel = getSocketChannel(selectionKey); if (socketChannel.isOpen() && selectionKey.isValid()) { // 事件分发,包含时间 onRead onAccept switch (selectionKey.readyOps()) { // Server接受连接 case SelectionKey.OP_ACCEPT: { NioServerSocket serverSocket = (NioServerSocket)socketContext; NioSocket socket = new NioSocket(serverSocket,socketChannel); session = socket.getSession(); EventTrigger.fireAcceptThread(session); break; } // 有数据读取 case SelectionKey.OP_READ: { int readSize = socketChannel.read(readTempBuffer); //判断连接是否关闭 if(MessageLoader.isRemoteClosed(readTempBuffer, readSize) && session.isConnected()){ session.getMessageLoader().setStopType(MessageLoader.StopType.STREAM_END); //如果 Socket 流达到结尾,则关闭连接 while(session.isConnected()) { if (session.getByteBufferChannel().size() == 0) { session.close(); } } break; }else if(readSize>0){ readTempBuffer.flip(); // 接收数据 if(session.getSSLParser()!=null && session.getSSLParser().isHandShakeDone()){ netByteBufferChannel.writeEnd(readTempBuffer); session.getSSLParser().unWarpByteBufferChannel(session, netByteBufferChannel, appByteBufferChannel); }else{ appByteBufferChannel.writeEnd(readTempBuffer); } readTempBuffer.clear(); } readTempBuffer.clear(); // 触发 onRead 事件,如果正在处理 onRead 事件则本次事件触发忽略 EventTrigger.fireReceiveThread(session); break; } default: { Logger.debug("Nothing to do ,SelectionKey is:" + selectionKey.readyOps()); } } selectionKeyIterator.remove(); } } } } } } catch (IOException e) { if((e instanceof AsynchronousCloseException) || (e instanceof ClosedChannelException)){ return; } if(e instanceof Exception){ //触发 onException 事件 EventTrigger.fireExceptionThread(session, e); } } finally{ // 触发连接断开事件 if(session!=null) { EventTrigger.fireDisconnect(session); TByteBuffer.release(readTempBuffer); } } } /** * 获取 socket 通道 * * @param selectionKey 当前 Selectionkey * @return SocketChannel 对象 * @throws IOException IO 异常 */ public SocketChannel getSocketChannel(SelectionKey selectionKey) throws IOException { SocketChannel socketChannel = null; // 取得通道 Object unknowChannel = selectionKey.channel(); // 根据通道的类来判断类型是 ServerSocketChannel 还是 SocketChannel if (unknowChannel instanceof ServerSocketChannel) { ServerSocketChannel serverSocketChannel = TObject.cast( unknowChannel ); socketChannel = serverSocketChannel.accept(); } else if (unknowChannel instanceof SocketChannel) { socketChannel = TObject.cast( unknowChannel ); } return socketChannel; } public void release(){ netByteBufferChannel.release(); } }