/* * Copyright 2015 Liu Huanting. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package fm.liu.timo.net; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.concurrent.atomic.AtomicBoolean; import fm.liu.timo.net.connection.AbstractConnection; /** * @author Liu Huanting 2015年5月9日 */ public class NIOActor { private volatile SelectionKey key; private final AbstractConnection con; private final SocketChannel channel; private final AtomicBoolean writing = new AtomicBoolean(false); public NIOActor(AbstractConnection con) { this.con = con; this.channel = con.getChannel(); } public void register(Selector selector) throws ClosedChannelException { key = channel.register(selector, SelectionKey.OP_READ, con); } public void read() throws IOException { ByteBuffer buffer = con.getReadBuffer(); if (buffer == null) { buffer = con.getProcessor().getBufferPool().allocate(); con.setReadBuffer(buffer); } int got = channel.read(buffer); if (got < 0) { con.close("stream closed"); return; } else if (got == 0) { if (!channel.isOpen()) { con.close("socket closed"); } return; } con.onRead(got); } public void check() { if (!writing.compareAndSet(false, true)) { return; } try { boolean finished = write(); writing.set(false); if (finished && con.getWriteQueue().isEmpty()) { if ((key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0)) { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); } } else { if ((key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) == 0)) { key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); } } } catch (IOException e) { con.close(e.getMessage()); } } private boolean write() throws IOException { int written = 0; ByteBuffer buffer = con.getWriteBuffer(); if (buffer != null) { while (buffer.hasRemaining()) { written = channel.write(buffer); if (written <= 0) { break; } else { con.getVariables().update(); } } if (buffer.hasRemaining()) { return false; } else { con.setWriteBuffer(null); con.recycle(buffer); } } while ((buffer = con.getWriteQueue().poll()) != null) { if (buffer.limit() == 0) { con.recycle(buffer); con.close("quit"); return true; } buffer.flip(); while (buffer.hasRemaining()) { written = channel.write(buffer); if (written <= 0) { break; } else { con.getVariables().update(); } } if (buffer.hasRemaining()) { con.setWriteBuffer(buffer); return false; } else { con.recycle(buffer); } } return true; } }