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

org.redkale.net.TcpAioAsyncConnection Maven / Gradle / Ivy

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.redkale.net;

import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import javax.net.ssl.SSLContext;

/**
 *
 * 

* 详情见: https://redkale.org * * @author zhangjx */ public class TcpAioAsyncConnection extends AsyncConnection { private final Semaphore semaphore = new Semaphore(1); private int readTimeoutSeconds; private int writeTimeoutSeconds; private final AsynchronousSocketChannel channel; private final SocketAddress remoteAddress; private BlockingQueue writeQueue; public TcpAioAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) { this.channel = ch; this.sslContext = sslContext; this.readTimeoutSeconds = readTimeoutSeconds; this.writeTimeoutSeconds = writeTimeoutSeconds; SocketAddress addr = addr0; if (addr == null) { try { addr = ch.getRemoteAddress(); } catch (Exception e) { //do nothing } } this.remoteAddress = addr; this.livingCounter = livingCounter; this.closedCounter = closedCounter; } @Override public boolean shutdownInput() { try { this.channel.shutdownInput(); return true; } catch (IOException e) { return false; } } @Override public boolean shutdownOutput() { try { this.channel.shutdownOutput(); return true; } catch (IOException e) { return false; } } @Override public boolean setOption(SocketOption name, T value) { try { this.channel.setOption(name, value); return true; } catch (IOException e) { return false; } } @Override public Set> supportedOptions() { return this.channel.supportedOptions(); } @Override public void read(ByteBuffer dst, A attachment, CompletionHandler handler) { this.readtime = System.currentTimeMillis(); if (readTimeoutSeconds > 0) { channel.read(dst, readTimeoutSeconds, TimeUnit.SECONDS, attachment, handler); } else { channel.read(dst, attachment, handler); } } @Override public void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler handler) { this.readtime = System.currentTimeMillis(); channel.read(dst, timeout < 0 ? 0 : timeout, unit, attachment, handler); } private void nextWrite(A attachment) { BlockingQueue queue = this.writeQueue; WriteEntry entry = queue == null ? null : queue.poll(); if (entry != null) { try { if (entry.writeOneBuffer == null) { write(false, entry.writeBuffers, entry.writeOffset, entry.writeLength, entry.writeAttachment, entry.writeHandler); } else { write(false, entry.writeOneBuffer, entry.writeAttachment, entry.writeHandler); } } catch (Exception e) { entry.writeHandler.failed(e, entry.writeAttachment); } } else { semaphore.release(); } } @Override public void write(ByteBuffer src, A attachment, CompletionHandler handler) { write(true, src, attachment, handler); } private void write(boolean acquire, ByteBuffer src, A attachment, CompletionHandler handler) { if (acquire && !semaphore.tryAcquire()) { if (this.writeQueue == null) { synchronized (semaphore) { if (this.writeQueue == null) { this.writeQueue = new LinkedBlockingDeque<>(); } } } this.writeQueue.add(new WriteEntry(src, attachment, handler)); return; } WriteOneCompletionHandler newHandler = new WriteOneCompletionHandler(src, handler); if (!channel.isOpen()) { newHandler.failed(new ClosedChannelException(), attachment); return; } this.writetime = System.currentTimeMillis(); try { if (writeTimeoutSeconds > 0) { channel.write(src, writeTimeoutSeconds, TimeUnit.SECONDS, attachment, newHandler); } else { channel.write(src, attachment, newHandler); } } catch (Exception e) { newHandler.failed(e, attachment); } } @Override public void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler handler) { write(true, srcs, offset, length, attachment, handler); } private void write(boolean acquire, ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler handler) { if (acquire && !semaphore.tryAcquire()) { if (this.writeQueue == null) { synchronized (semaphore) { if (this.writeQueue == null) { this.writeQueue = new LinkedBlockingDeque<>(); } } } this.writeQueue.add(new WriteEntry(srcs, offset, length, attachment, handler)); return; } WriteMoreCompletionHandler newHandler = new WriteMoreCompletionHandler(srcs, offset, length, handler); if (!channel.isOpen()) { newHandler.failed(new ClosedChannelException(), attachment); return; } this.writetime = System.currentTimeMillis(); try { channel.write(srcs, offset, length, writeTimeoutSeconds > 0 ? writeTimeoutSeconds : 60, TimeUnit.SECONDS, attachment, newHandler); } catch (Exception e) { newHandler.failed(e, attachment); } } @Override public void setReadTimeoutSeconds(int readTimeoutSeconds) { this.readTimeoutSeconds = readTimeoutSeconds; } @Override public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { this.writeTimeoutSeconds = writeTimeoutSeconds; } @Override public int getReadTimeoutSeconds() { return this.readTimeoutSeconds; } @Override public int getWriteTimeoutSeconds() { return this.writeTimeoutSeconds; } @Override public final SocketAddress getRemoteAddress() { return remoteAddress; } @Override public SocketAddress getLocalAddress() { try { return channel.getLocalAddress(); } catch (IOException e) { return null; } } @Override public final Future read(ByteBuffer dst) { return channel.read(dst); } @Override public final Future write(ByteBuffer src) { return channel.write(src); } @Override public final void close() throws IOException { super.close(); channel.close(); BlockingQueue queue = this.writeQueue; if (queue == null) return; WriteEntry entry; Exception ex = null; while ((entry = queue.poll()) != null) { if (ex == null) ex = new ClosedChannelException(); try { entry.writeHandler.failed(ex, entry.writeAttachment); } catch (Exception e) { } } } @Override public final boolean isOpen() { return channel.isOpen(); } @Override public final boolean isTCP() { return true; } private class WriteMoreCompletionHandler implements CompletionHandler { private final CompletionHandler writeHandler; private final ByteBuffer[] writeBuffers; private int writeOffset; private int writeLength; private int writeCount; public WriteMoreCompletionHandler(ByteBuffer[] buffers, int offset, int length, CompletionHandler handler) { this.writeBuffers = buffers; this.writeOffset = offset; this.writeLength = length; this.writeHandler = handler; } @Override public void completed(Long result, A attachment) { if (result >= 0) { writeCount += result; try { int index = -1; for (int i = writeOffset; i < (writeOffset + writeLength); i++) { if (writeBuffers[i].hasRemaining()) { index = i; break; } } if (index >= 0) { writeOffset += index; writeLength -= index; channel.write(writeBuffers, writeOffset, writeLength, writeTimeoutSeconds > 0 ? writeTimeoutSeconds : 60, TimeUnit.SECONDS, attachment, this); return; } } catch (Exception e) { failed(e, attachment); return; } nextWrite(attachment); writeHandler.completed(writeCount, attachment); } else { nextWrite(attachment); writeHandler.completed(result.intValue(), attachment); } } @Override public void failed(Throwable exc, A attachment) { nextWrite(attachment); writeHandler.failed(exc, attachment); } } private class WriteOneCompletionHandler implements CompletionHandler { private final CompletionHandler writeHandler; private final ByteBuffer writeOneBuffer; public WriteOneCompletionHandler(ByteBuffer buffer, CompletionHandler handler) { this.writeOneBuffer = buffer; this.writeHandler = handler; } @Override public void completed(Integer result, A attachment) { try { if (writeOneBuffer.hasRemaining()) { channel.write(writeOneBuffer, attachment, this); return; } } catch (Exception e) { failed(e, attachment); return; } nextWrite(attachment); writeHandler.completed(result, attachment); } @Override public void failed(Throwable exc, A attachment) { nextWrite(attachment); writeHandler.failed(exc, attachment); } } private static class WriteEntry { ByteBuffer writeOneBuffer; ByteBuffer[] writeBuffers; int writingCount; int writeOffset; int writeLength; Object writeAttachment; CompletionHandler writeHandler; public WriteEntry(ByteBuffer writeOneBuffer, Object writeAttachment, CompletionHandler writeHandler) { this.writeOneBuffer = writeOneBuffer; this.writeAttachment = writeAttachment; this.writeHandler = writeHandler; } public WriteEntry(ByteBuffer[] writeBuffers, int writeOffset, int writeLength, Object writeAttachment, CompletionHandler writeHandler) { this.writeBuffers = writeBuffers; this.writeOffset = writeOffset; this.writeLength = writeLength; this.writeAttachment = writeAttachment; this.writeHandler = writeHandler; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy