All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aoju.bus.socket.origin.TcpAioSession Maven / Gradle / Ivy

There is a newer version: 8.0.0
Show newest version
/*
 * The MIT License
 *
 * Copyright (c) 2017 aoju.org All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.aoju.bus.socket.origin;


import org.aoju.bus.core.io.segment.BufferPage;
import org.aoju.bus.core.io.segment.VirtualBuffer;
import org.aoju.bus.logger.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * AIO传输层会话。
 *
 * 

* AioSession为最核心的类,封装{@link AsynchronousSocketChannel} API接口,简化IO操作。 *

*

* 其中开放给用户使用的接口为: *

    *
  1. {@link TcpAioSession#close()}
  2. *
  3. {@link TcpAioSession#close(boolean)}
  4. *
  5. {@link TcpAioSession#getAttachment()}
  6. *
  7. {@link TcpAioSession#getInputStream()}
  8. *
  9. {@link TcpAioSession#getInputStream(int)}
  10. *
  11. {@link TcpAioSession#getLocalAddress()}
  12. *
  13. {@link TcpAioSession#getRemoteAddress()}
  14. *
  15. {@link TcpAioSession#getSessionID()}
  16. *
  17. {@link TcpAioSession#isInvalid()}
  18. *
  19. {@link TcpAioSession#setAttachment(Object)}
  20. *
* *

* * @author Kimi Liu * @version 5.0.8 * @since JDK 1.8+ */ class TcpAioSession extends AioSession { /** * 底层通信channel对象 */ protected AsynchronousSocketChannel channel; /** * 读缓冲。 *

大小取决于AioQuickClient/AioQuickServer设置的setReadBufferSize

*/ protected VirtualBuffer readBuffer; /** * 写缓冲 */ protected VirtualBuffer writeBuffer; /** * 会话当前状态 * * @see TcpAioSession#SESSION_STATUS_CLOSED * @see TcpAioSession#SESSION_STATUS_CLOSING * @see TcpAioSession#SESSION_STATUS_ENABLED */ protected byte status = SESSION_STATUS_ENABLED; /** * 输出信号量,防止并发write导致异常 */ private Semaphore semaphore = new Semaphore(1); private TcpReadHandler readCompletionHandler; private TcpWriteHandler writeCompletionHandler; private ServerConfig ioServerConfig; private InputStream inputStream; private WriteBuffer byteBuf; /** * @param channel * @param config * @param readCompletionHandler * @param writeCompletionHandler * @param bufferPage 是否服务端Session */ TcpAioSession(AsynchronousSocketChannel channel, final ServerConfig config, TcpReadHandler readCompletionHandler, TcpWriteHandler writeCompletionHandler, BufferPage bufferPage) { this.channel = channel; this.readCompletionHandler = readCompletionHandler; this.writeCompletionHandler = writeCompletionHandler; this.ioServerConfig = config; this.readBuffer = bufferPage.allocate(config.getReadBufferSize()); byteBuf = new WriteBuffer(bufferPage, new Function() { @Override public Void apply(WriteBuffer var) { if (!semaphore.tryAcquire()) { return null; } TcpAioSession.this.writeBuffer = var.poll(); if (writeBuffer == null) { semaphore.release(); } else { continueWrite(writeBuffer); } return null; } }, ioServerConfig.getWriteQueueCapacity()); //触发状态机 config.getProcessor().stateEvent(this, StateMachine.NEW_SESSION, null); } /** * 初始化AioSession */ void initSession() { continueRead(); } /** * 触发AIO的写操作, *

需要调用控制同步

*/ void writeToChannel() { if (writeBuffer == null) { writeBuffer = byteBuf.poll(); } else if (!writeBuffer.buffer().hasRemaining()) { writeBuffer.clean(); writeBuffer = byteBuf.poll(); } if (writeBuffer != null) { continueWrite(writeBuffer); return; } semaphore.release(); //此时可能是Closing或Closed状态 if (status != SESSION_STATUS_ENABLED) { close(); } else if (!byteBuf.isClosed()) { //也许此时有新的消息通过write方法添加到writeCacheQueue中 byteBuf.flush(); } } /** * 内部方法:触发通道的读操作 * * @param buffer */ protected final void readFromChannel0(ByteBuffer buffer) { channel.read(buffer, this, readCompletionHandler); } /** * 内部方法:触发通道的写操作 */ protected final void writeToChannel0(ByteBuffer buffer) { channel.write(buffer, 0L, TimeUnit.MILLISECONDS, this, writeCompletionHandler); } public final WriteBuffer writeBuffer() { return byteBuf; } // // /** // * 强制关闭当前AIOSession。 // *

若此时还存留待输出的数据,则会导致该部分数据丢失

// */ // public final void close() { // close(true); // } /** * 是否立即关闭会话 * * @param immediate true:立即关闭,false:响应消息发送完后关闭 */ public synchronized void close(boolean immediate) { //status == SESSION_STATUS_CLOSED说明close方法被重复调用 if (status == SESSION_STATUS_CLOSED) { Logger.warn("ignore, session:{} is closed:", getSessionID()); return; } status = immediate ? SESSION_STATUS_CLOSED : SESSION_STATUS_CLOSING; if (immediate) { try { if (!byteBuf.isClosed()) { byteBuf.close(); } byteBuf = null; } catch (IOException e) { e.printStackTrace(); } readBuffer.clean(); readBuffer = null; if (writeBuffer != null) { writeBuffer.clean(); writeBuffer = null; } try { channel.shutdownInput(); } catch (IOException e) { Logger.debug(e.getMessage(), e); } try { channel.shutdownOutput(); } catch (IOException e) { Logger.debug(e.getMessage(), e); } try { channel.close(); } catch (IOException e) { Logger.debug("close session exception", e); } ioServerConfig.getProcessor().stateEvent(this, StateMachine.SESSION_CLOSED, null); } else if ((writeBuffer == null || !writeBuffer.buffer().hasRemaining()) && !byteBuf.hasData()) { close(true); } else { ioServerConfig.getProcessor().stateEvent(this, StateMachine.SESSION_CLOSING, null); if (!byteBuf.isClosed()) { byteBuf.flush(); } } } /** * 获取当前Session的唯一标识 */ public final String getSessionID() { return "aioSession-" + hashCode(); } /** * 当前会话是否已失效 */ public final boolean isInvalid() { return status != SESSION_STATUS_ENABLED; } /** * 触发通道的读回调操作 */ void readFromChannel(boolean eof) { if (status == SESSION_STATUS_CLOSED) { return; } final ByteBuffer readBuffer = this.readBuffer.buffer(); readBuffer.flip(); final Message messageProcessor = ioServerConfig.getProcessor(); while (readBuffer.hasRemaining() && status == SESSION_STATUS_ENABLED) { T dataEntry = null; try { dataEntry = ioServerConfig.getProtocol().decode(readBuffer, this); } catch (Exception e) { messageProcessor.stateEvent(this, StateMachine.DECODE_EXCEPTION, e); throw e; } if (dataEntry == null) { break; } //处理消息 try { messageProcessor.process(this, dataEntry); } catch (Exception e) { messageProcessor.stateEvent(this, StateMachine.PROCESS_EXCEPTION, e); } } if (eof || status == SESSION_STATUS_CLOSING) { close(false); messageProcessor.stateEvent(this, StateMachine.INPUT_SHUTDOWN, null); return; } if (status == SESSION_STATUS_CLOSED) { return; } //数据读取完毕 if (readBuffer.remaining() == 0) { readBuffer.clear(); } else if (readBuffer.position() > 0) { // 仅当发生数据读取时调用compact,减少内存拷贝 readBuffer.compact(); } else { readBuffer.position(readBuffer.limit()); readBuffer.limit(readBuffer.capacity()); } //读缓冲区已满 if (!readBuffer.hasRemaining()) { RuntimeException exception = new RuntimeException("readBuffer has no remaining"); messageProcessor.stateEvent(this, StateMachine.DECODE_EXCEPTION, exception); throw exception; } if (byteBuf != null && !byteBuf.isClosed()) { byteBuf.flush(); } continueRead(); } protected void continueRead() { readFromChannel0(readBuffer.buffer()); } protected void continueWrite(VirtualBuffer writeBuffer) { writeToChannel0(writeBuffer.buffer()); } /** * @see AsynchronousSocketChannel#getLocalAddress() */ public final InetSocketAddress getLocalAddress() throws IOException { assertChannel(); return (InetSocketAddress) channel.getLocalAddress(); } /** * @see AsynchronousSocketChannel#getRemoteAddress() */ public final InetSocketAddress getRemoteAddress() throws IOException { assertChannel(); return (InetSocketAddress) channel.getRemoteAddress(); } private void assertChannel() throws IOException { if (status == SESSION_STATUS_CLOSED || channel == null) { throw new IOException("session is closed"); } } ServerConfig getServerConfig() { return this.ioServerConfig; } /** * 获得数据输入流对象。 *

* faster模式下调用该方法会触发UnsupportedOperationException异常。 *

*

* MessageProcessor采用异步处理消息的方式时,调用该方法可能会出现异常。 *

*/ public InputStream getInputStream() throws IOException { return inputStream == null ? getInputStream(-1) : inputStream; } /** * 获取已知长度的InputStream * * @param length InputStream长度 */ public InputStream getInputStream(int length) throws IOException { if (inputStream != null) { throw new IOException("pre inputStream has not closed"); } if (inputStream != null) { return inputStream; } synchronized (this) { if (inputStream == null) { inputStream = new InnerInputStream(length); } } return inputStream; } private class InnerInputStream extends InputStream { private int remainLength; public InnerInputStream(int length) { this.remainLength = length >= 0 ? length : -1; } @Override public int read() throws IOException { if (remainLength == 0) { return -1; } ByteBuffer readBuffer = TcpAioSession.this.readBuffer.buffer(); if (readBuffer.hasRemaining()) { remainLength--; return readBuffer.get(); } readBuffer.clear(); try { int readSize = channel.read(readBuffer).get(); readBuffer.flip(); if (readSize == -1) { remainLength = 0; return -1; } else { return read(); } } catch (Exception e) { throw new IOException(e); } } @Override public int available() throws IOException { return remainLength == 0 ? 0 : readBuffer.buffer().remaining(); } @Override public void close() throws IOException { if (TcpAioSession.this.inputStream == InnerInputStream.this) { TcpAioSession.this.inputStream = null; } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy