AsyncConnection接口大变动
This commit is contained in:
@@ -12,8 +12,9 @@ import java.nio.channels.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.*;
|
import java.util.concurrent.atomic.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import org.redkale.util.ObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -22,7 +23,7 @@ import javax.net.ssl.SSLContext;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCloseable {
|
public abstract class AsyncConnection implements ReadableByteChannel, WritableByteChannel, AutoCloseable {
|
||||||
|
|
||||||
protected SSLContext sslContext;
|
protected SSLContext sslContext;
|
||||||
|
|
||||||
@@ -34,6 +35,12 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
protected volatile long writetime;
|
protected volatile long writetime;
|
||||||
|
|
||||||
|
protected final Supplier<ByteBuffer> bufferSupplier;
|
||||||
|
|
||||||
|
protected final Consumer<ByteBuffer> bufferConsumer;
|
||||||
|
|
||||||
|
protected ByteBuffer readBuffer;
|
||||||
|
|
||||||
//在线数
|
//在线数
|
||||||
protected AtomicLong livingCounter;
|
protected AtomicLong livingCounter;
|
||||||
|
|
||||||
@@ -45,6 +52,22 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
//关联的事件数, 小于1表示没有事件
|
//关联的事件数, 小于1表示没有事件
|
||||||
protected final AtomicInteger eventing = new AtomicInteger();
|
protected final AtomicInteger eventing = new AtomicInteger();
|
||||||
|
|
||||||
|
protected AsyncConnection(Context context) {
|
||||||
|
this(context.getBufferSupplier(), context.getBufferConsumer(), context.getSSLContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsyncConnection(ObjectPool<ByteBuffer> bufferPool, SSLContext sslContext) {
|
||||||
|
this(bufferPool, bufferPool, sslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, SSLContext sslContext) {
|
||||||
|
Objects.requireNonNull(bufferSupplier);
|
||||||
|
Objects.requireNonNull(bufferConsumer);
|
||||||
|
this.bufferSupplier = bufferSupplier;
|
||||||
|
this.bufferConsumer = bufferConsumer;
|
||||||
|
this.sslContext = sslContext;
|
||||||
|
}
|
||||||
|
|
||||||
public final long getLastReadTime() {
|
public final long getLastReadTime() {
|
||||||
return readtime;
|
return readtime;
|
||||||
}
|
}
|
||||||
@@ -61,6 +84,9 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
return eventing.decrementAndGet();
|
return eventing.decrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract boolean isOpen();
|
||||||
|
|
||||||
public abstract boolean isTCP();
|
public abstract boolean isTCP();
|
||||||
|
|
||||||
public abstract boolean shutdownInput();
|
public abstract boolean shutdownInput();
|
||||||
@@ -84,17 +110,15 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract Future<Integer> read(ByteBuffer dst);
|
public abstract int read(ByteBuffer dst) throws IOException;
|
||||||
|
|
||||||
|
public abstract void read(CompletionHandler<Integer, ByteBuffer> handler);
|
||||||
|
|
||||||
|
public abstract void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract int write(ByteBuffer src) throws IOException;
|
||||||
|
|
||||||
public abstract <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract Future<Integer> write(ByteBuffer src);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
@@ -103,6 +127,36 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
|
|
||||||
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
|
||||||
|
|
||||||
|
public void setReadBuffer(ByteBuffer buffer) {
|
||||||
|
if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer");
|
||||||
|
this.readBuffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer pollReadBuffer() {
|
||||||
|
ByteBuffer rs = this.readBuffer;
|
||||||
|
if (rs != null) {
|
||||||
|
this.readBuffer = null;
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(ByteBuffer buffer) {
|
||||||
|
if (buffer == null) return;
|
||||||
|
bufferConsumer.accept(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void offerBuffer(ByteBuffer... buffers) {
|
||||||
|
if (buffers == null) return;
|
||||||
|
for (ByteBuffer buffer : buffers) {
|
||||||
|
bufferConsumer.accept(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer pollWriteBuffer() {
|
||||||
|
return bufferSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose() {//同close, 只是去掉throws IOException
|
public void dispose() {//同close, 只是去掉throws IOException
|
||||||
try {
|
try {
|
||||||
this.close();
|
this.close();
|
||||||
@@ -125,11 +179,15 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
livingCounter.decrementAndGet();
|
livingCounter.decrementAndGet();
|
||||||
livingCounter = null;
|
livingCounter = null;
|
||||||
}
|
}
|
||||||
if (beforeCloseListener != null)
|
if (beforeCloseListener != null) {
|
||||||
try {
|
try {
|
||||||
beforeCloseListener.accept(this);
|
beforeCloseListener.accept(this);
|
||||||
} catch (Exception io) {
|
} catch (Exception io) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (this.readBuffer != null) {
|
||||||
|
bufferConsumer.accept(this.readBuffer);
|
||||||
|
}
|
||||||
if (attributes == null) return;
|
if (attributes == null) return;
|
||||||
try {
|
try {
|
||||||
for (Object obj : attributes.values()) {
|
for (Object obj : attributes.values()) {
|
||||||
@@ -174,6 +232,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
/**
|
/**
|
||||||
* 创建TCP协议客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
|
* @param bufferPool ByteBuffer对象池
|
||||||
* @param address 连接点子
|
* @param address 连接点子
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param group 连接AsynchronousChannelGroup
|
||||||
* @param readTimeoutSeconds 读取超时秒数
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
@@ -181,14 +240,31 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
*
|
*
|
||||||
* @return 连接CompletableFuture
|
* @return 连接CompletableFuture
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SocketAddress address,
|
public static CompletableFuture<AsyncConnection> createTCP(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousChannelGroup group,
|
||||||
final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
return createTCP(group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
return createTCP(bufferPool, group, null, address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建TCP协议客户端连接
|
* 创建TCP协议客户端连接
|
||||||
*
|
*
|
||||||
|
* @param context Context
|
||||||
|
* @param address 连接点子
|
||||||
|
* @param group 连接AsynchronousChannelGroup
|
||||||
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
|
* @param writeTimeoutSeconds 写入超时秒数
|
||||||
|
*
|
||||||
|
* @return 连接CompletableFuture
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<AsyncConnection> createTCP(final Context context, final AsynchronousChannelGroup group,
|
||||||
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return createTCP(context.getBufferSupplier(), context.getBufferConsumer(), group, context.getSSLContext(), address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建TCP协议客户端连接
|
||||||
|
*
|
||||||
|
* @param bufferPool ByteBuffer对象池
|
||||||
* @param address 连接点子
|
* @param address 连接点子
|
||||||
* @param sslContext SSLContext
|
* @param sslContext SSLContext
|
||||||
* @param group 连接AsynchronousChannelGroup
|
* @param group 连接AsynchronousChannelGroup
|
||||||
@@ -197,7 +273,25 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
*
|
*
|
||||||
* @return 连接CompletableFuture
|
* @return 连接CompletableFuture
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<AsyncConnection> createTCP(final AsynchronousChannelGroup group, final SSLContext sslContext,
|
public static CompletableFuture<AsyncConnection> createTCP(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousChannelGroup group, final SSLContext sslContext,
|
||||||
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return createTCP(bufferPool, bufferPool, group, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建TCP协议客户端连接
|
||||||
|
*
|
||||||
|
* @param bufferSupplier ByteBuffer生产器
|
||||||
|
* @param bufferConsumer ByteBuffer回收器
|
||||||
|
* @param address 连接点子
|
||||||
|
* @param sslContext SSLContext
|
||||||
|
* @param group 连接AsynchronousChannelGroup
|
||||||
|
* @param readTimeoutSeconds 读取超时秒数
|
||||||
|
* @param writeTimeoutSeconds 写入超时秒数
|
||||||
|
*
|
||||||
|
* @return 连接CompletableFuture
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<AsyncConnection> createTCP(final Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer, final AsynchronousChannelGroup group, final SSLContext sslContext,
|
||||||
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
final CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
|
final CompletableFuture<AsyncConnection> future = new CompletableFuture<>();
|
||||||
try {
|
try {
|
||||||
@@ -211,7 +305,7 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
channel.connect(address, null, new CompletionHandler<Void, Void>() {
|
channel.connect(address, null, new CompletionHandler<Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Void result, Void attachment) {
|
public void completed(Void result, Void attachment) {
|
||||||
future.complete(create(channel, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds));
|
future.complete(new TcpAioAsyncConnection(bufferSupplier, bufferConsumer, channel, sslContext, address, readTimeoutSeconds, writeTimeoutSeconds, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -225,80 +319,109 @@ public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCl
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// public static AsyncConnection create(final Socket socket) {
|
||||||
* 通常用于 ssl socket
|
// return create(socket, null, 0, 0);
|
||||||
*
|
// }
|
||||||
* @param socket Socket对象
|
// public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
||||||
*
|
// return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, null, null);
|
||||||
* @return 连接对象
|
// }
|
||||||
*/
|
//
|
||||||
public static AsyncConnection create(final Socket socket) {
|
// public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0,
|
||||||
return create(socket, null, 0, 0);
|
// final int writeTimeoutSecond0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
}
|
// return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, livingCounter, closedCounter);
|
||||||
|
// }
|
||||||
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
|
//
|
||||||
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, null, null);
|
// public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
||||||
}
|
// final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
|
// return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0,
|
// }
|
||||||
final int writeTimeoutSecond0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
//
|
||||||
return new TcpBioAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0, livingCounter, closedCounter);
|
// public static AsyncConnection create(final SocketChannel ch, final SocketAddress addr0, final Selector selector, final Context context) {
|
||||||
}
|
// return new TcpNioAsyncConnection(ch, addr0, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
||||||
|
// }
|
||||||
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
//
|
||||||
|
// public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
||||||
|
// final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
|
// final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
// return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
|
// }
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch,
|
||||||
|
SocketAddress addr, final boolean client0,
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, null, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final SocketChannel ch, final SocketAddress addr0, final Selector selector, final Context context) {
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch,
|
||||||
return new TcpNioAsyncConnection(ch, addr0, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
SocketAddress addr, final boolean client0,
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncConnection create(final SocketChannel ch, SocketAddress addr, final Selector selector,
|
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpNioAsyncConnection(ch, addr, selector, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, null, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch, SSLContext sslContext,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
SocketAddress addr, final boolean client0,
|
||||||
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0) {
|
||||||
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final DatagramChannel ch, SSLContext sslContext,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
SocketAddress addr, final boolean client0,
|
||||||
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new UdpBioAsyncConnection(ch, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
return new UdpBioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr, client0, readTimeoutSeconds0, writeTimeoutSeconds0, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch) {
|
||||||
return create(ch, null, 0, 0);
|
return create(context, ch, (SocketAddress) null, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final Context context) {
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSeconds,
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch,
|
||||||
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpAioAsyncConnection(ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, SSLContext sslContext, final SocketAddress addr0, final int readTimeoutSeconds,
|
public static AsyncConnection create(final Context context, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
return new TcpAioAsyncConnection(ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
return new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0,
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch) {
|
||||||
final Context context, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
return create(bufferPool, ch, null, 0, 0);
|
||||||
return new TcpAioAsyncConnection(ch, context.sslContext, addr0, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, null, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncConnection create(final ObjectPool<ByteBuffer> bufferPool, final AsynchronousSocketChannel ch, SSLContext sslContext,
|
||||||
|
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds, final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
return new TcpAioAsyncConnection(bufferPool, bufferPool, ch, sslContext, addr0, readTimeoutSeconds, writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,14 +55,13 @@ public class PrepareRunner implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response == null) response = responsePool.get();
|
if (response == null) response = responsePool.get();
|
||||||
final ByteBuffer buffer = response.request.pollReadBuffer();
|
|
||||||
try {
|
try {
|
||||||
channel.read(buffer, keepalive ? context.getAliveTimeoutSeconds() : 0, TimeUnit.SECONDS, null,
|
channel.read(keepalive ? context.getAliveTimeoutSeconds() : 0, TimeUnit.SECONDS,
|
||||||
new CompletionHandler<Integer, Void>() {
|
new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment1) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
response.request.offerReadBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -85,8 +84,8 @@ public class PrepareRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer buffer) {
|
||||||
response.request.offerReadBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -96,7 +95,6 @@ public class PrepareRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception te) {
|
} catch (Exception te) {
|
||||||
response.request.offerReadBuffer(buffer);
|
|
||||||
channel.dispose();// response.init(channel); 在调用之前异常
|
channel.dispose();// response.init(channel); 在调用之前异常
|
||||||
response.removeChannel();
|
response.removeChannel();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
@@ -126,19 +124,4 @@ public class PrepareRunner implements Runnable {
|
|||||||
return response.removeChannel();
|
return response.removeChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Request request) {
|
|
||||||
return request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer(Response response) {
|
|
||||||
return response.request.pollReadBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Request request, ByteBuffer buffer) {
|
|
||||||
request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(Response response, ByteBuffer buffer) {
|
|
||||||
response.request.offerReadBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,15 +213,16 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
public void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
|
public void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
|
||||||
executeCounter.incrementAndGet();
|
executeCounter.incrementAndGet();
|
||||||
final int rs = request.readHeader(buffer);
|
final int rs = request.readHeader(buffer);
|
||||||
if (rs < 0) {
|
final AsyncConnection channel = request.channel;
|
||||||
request.offerReadBuffer(buffer);
|
if (rs < 0) { //表示数据格式不正确
|
||||||
|
channel.offerBuffer(buffer);
|
||||||
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
|
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
request.setMoredata(buffer);
|
request.setMoredata(buffer);
|
||||||
} else {
|
} else {
|
||||||
request.offerReadBuffer(buffer);
|
channel.offerBuffer(buffer);
|
||||||
}
|
}
|
||||||
request.prepare();
|
request.prepare();
|
||||||
response.filter = this.headFilter;
|
response.filter = this.headFilter;
|
||||||
@@ -229,21 +230,23 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
response.nextEvent();
|
response.nextEvent();
|
||||||
} else {
|
} else {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
channel.setReadBuffer(buffer);
|
||||||
final AtomicInteger ai = new AtomicInteger(rs);
|
final AtomicInteger ai = new AtomicInteger(rs);
|
||||||
request.channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
channel.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
buffer.flip();
|
attachment.flip();
|
||||||
ai.addAndGet(-request.readBody(buffer));
|
ai.addAndGet(-request.readBody(attachment));
|
||||||
if (ai.get() > 0) {
|
if (ai.get() > 0) {
|
||||||
buffer.clear();
|
attachment.clear();
|
||||||
request.channel.read(buffer, buffer, this);
|
channel.setReadBuffer(attachment);
|
||||||
|
channel.read(this);
|
||||||
} else {
|
} else {
|
||||||
if (buffer.hasRemaining()) {
|
if (attachment.hasRemaining()) {
|
||||||
request.setMoredata(buffer);
|
request.setMoredata(attachment);
|
||||||
} else {
|
} else {
|
||||||
request.offerReadBuffer(buffer);
|
channel.offerBuffer(attachment);
|
||||||
}
|
}
|
||||||
request.prepare();
|
request.prepare();
|
||||||
try {
|
try {
|
||||||
@@ -261,7 +264,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
illRequestCounter.incrementAndGet();
|
illRequestCounter.incrementAndGet();
|
||||||
request.offerReadBuffer(buffer);
|
channel.offerBuffer(attachment);
|
||||||
response.finish(true);
|
response.finish(true);
|
||||||
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, forece to close channel ", exc);
|
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, forece to close channel ", exc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,13 +73,13 @@ public abstract class ProtocolServer {
|
|||||||
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
} else if ("aio".equalsIgnoreCase(netimpl)) {
|
||||||
return new TcpAioProtocolServer(context);
|
return new TcpAioProtocolServer(context);
|
||||||
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
} else if ("nio".equalsIgnoreCase(netimpl)) {
|
||||||
return new TcpNioProtocolServer(context);
|
return null;// return new TcpNioProtocolServer(context);
|
||||||
}
|
}
|
||||||
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
} else if ("UDP".equalsIgnoreCase(protocol)) {
|
||||||
if (netimpl == null || netimpl.isEmpty()) {
|
if (netimpl == null || netimpl.isEmpty()) {
|
||||||
return new UdpBioProtocolServer(context);
|
return null;// return new UdpBioProtocolServer(context);
|
||||||
} else if ("bio".equalsIgnoreCase(netimpl)) {
|
} else if ("bio".equalsIgnoreCase(netimpl)) {
|
||||||
return new UdpBioProtocolServer(context);
|
return null;// return new UdpBioProtocolServer(context);
|
||||||
}
|
}
|
||||||
} else if (netimpl == null || netimpl.isEmpty()) {
|
} else if (netimpl == null || netimpl.isEmpty()) {
|
||||||
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
|
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected AsyncConnection channel;
|
protected AsyncConnection channel;
|
||||||
|
|
||||||
protected ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
* properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留;
|
||||||
* properties 通常存放需要永久绑定在request里的一些对象
|
* properties 通常存放需要永久绑定在request里的一些对象
|
||||||
@@ -49,7 +47,6 @@ public abstract class Request<C extends Context> {
|
|||||||
|
|
||||||
protected Request(C context) {
|
protected Request(C context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.readBuffer = context.pollBuffer();
|
|
||||||
this.bsonConvert = context.getBsonConvert();
|
this.bsonConvert = context.getBsonConvert();
|
||||||
this.jsonConvert = context.getJsonConvert();
|
this.jsonConvert = context.getJsonConvert();
|
||||||
}
|
}
|
||||||
@@ -64,23 +61,6 @@ public abstract class Request<C extends Context> {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ByteBuffer pollReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
if (buffer == null) buffer = context.pollBuffer();
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void offerReadBuffer(ByteBuffer buffer) {
|
|
||||||
if (buffer == null) return;
|
|
||||||
if (this.readBuffer == null) {
|
|
||||||
buffer.clear();
|
|
||||||
this.readBuffer = buffer;
|
|
||||||
} else {
|
|
||||||
context.offerBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
* 返回值:Integer.MIN_VALUE: 帧数据; -1:数据不合法; 0:解析完毕; >0: 需再读取的字节数。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.nio.channels.*;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.*;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,11 +36,12 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
|
|
||||||
private BlockingQueue<WriteEntry> writeQueue;
|
private BlockingQueue<WriteEntry> writeQueue;
|
||||||
|
|
||||||
public TcpAioAsyncConnection(final AsynchronousSocketChannel ch, SSLContext sslContext,
|
public TcpAioAsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer,
|
||||||
final SocketAddress addr0, final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
final AsynchronousSocketChannel ch, final SSLContext sslContext, final SocketAddress addr0,
|
||||||
|
final int readTimeoutSeconds, final int writeTimeoutSeconds,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
super(bufferSupplier, bufferConsumer, sslContext);
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.sslContext = sslContext;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
this.readTimeoutSeconds = readTimeoutSeconds;
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
||||||
SocketAddress addr = addr0;
|
SocketAddress addr = addr0;
|
||||||
@@ -91,19 +93,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
|
ByteBuffer dst = pollReadBuffer();
|
||||||
if (readTimeoutSeconds > 0) {
|
if (readTimeoutSeconds > 0) {
|
||||||
channel.read(dst, readTimeoutSeconds, TimeUnit.SECONDS, attachment, handler);
|
channel.read(dst, readTimeoutSeconds, TimeUnit.SECONDS, dst, handler);
|
||||||
} else {
|
} else {
|
||||||
channel.read(dst, attachment, handler);
|
channel.read(dst, dst, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
channel.read(dst, timeout < 0 ? 0 : timeout, unit, attachment, handler);
|
ByteBuffer dst = pollReadBuffer();
|
||||||
|
channel.read(dst, timeout < 0 ? 0 : timeout, unit, dst, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <A> void nextWrite(A attachment) {
|
private <A> void nextWrite(A attachment) {
|
||||||
@@ -223,13 +227,21 @@ public class TcpAioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> read(ByteBuffer dst) {
|
public final int read(ByteBuffer dst) throws IOException {
|
||||||
return channel.read(dst);
|
try {
|
||||||
|
return channel.read(dst).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Future<Integer> write(ByteBuffer src) {
|
public final int write(ByteBuffer src) throws IOException {
|
||||||
return channel.write(src);
|
try {
|
||||||
|
return channel.write(src).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class TcpAioProtocolServer extends ProtocolServer {
|
|||||||
@Override
|
@Override
|
||||||
public void open(AnyValue config) throws IOException {
|
public void open(AnyValue config) throws IOException {
|
||||||
//group = AsynchronousChannelGroup.withThreadPool(context.executor);
|
//group = AsynchronousChannelGroup.withThreadPool(context.executor);
|
||||||
group = AsynchronousChannelGroup.withFixedThreadPool(context.executor.getCorePoolSize(), context.executor.getThreadFactory());
|
group = AsynchronousChannelGroup.withFixedThreadPool(context.executor.getCorePoolSize(), context.executor.getThreadFactory());
|
||||||
this.serverChannel = AsynchronousServerSocketChannel.open(group);
|
this.serverChannel = AsynchronousServerSocketChannel.open(group);
|
||||||
|
|
||||||
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
|
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
|
||||||
@@ -95,9 +95,8 @@ public class TcpAioProtocolServer extends ProtocolServer {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
context.logger.log(Level.INFO, channel + " setOption error", e);
|
context.logger.log(Level.INFO, channel + " setOption error", e);
|
||||||
}
|
}
|
||||||
AsyncConnection conn = new TcpAioAsyncConnection(channel, context.sslContext, null, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
AsyncConnection conn = new TcpAioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), channel,
|
||||||
conn.livingCounter = livingCounter;
|
context.getSSLContext(), null, context.readTimeoutSeconds, context.writeTimeoutSeconds, livingCounter, closedCounter);
|
||||||
conn.closedCounter = closedCounter;
|
|
||||||
context.runAsync(new PrepareRunner(context, conn, null, null));
|
context.runAsync(new PrepareRunner(context, conn, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,240 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpBioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
|
||||||
|
|
||||||
private static Set<SocketOption<?>> defaultOptions() {
|
|
||||||
HashSet<SocketOption<?>> set = new HashSet<>(5);
|
|
||||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
|
||||||
set.add(StandardSocketOptions.SO_KEEPALIVE);
|
|
||||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
|
||||||
set.add(StandardSocketOptions.TCP_NODELAY);
|
|
||||||
return Collections.unmodifiableSet(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readTimeoutSeconds;
|
|
||||||
|
|
||||||
private int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
private final Socket socket;
|
|
||||||
|
|
||||||
private final ReadableByteChannel readChannel;
|
|
||||||
|
|
||||||
private final WritableByteChannel writeChannel;
|
|
||||||
|
|
||||||
private final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
public TcpBioAsyncConnection(final Socket socket, final SocketAddress addr0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.socket = socket;
|
|
||||||
ReadableByteChannel rc = null;
|
|
||||||
WritableByteChannel wc = null;
|
|
||||||
try {
|
|
||||||
socket.setSoTimeout(Math.max(readTimeoutSeconds0, writeTimeoutSeconds0));
|
|
||||||
rc = Channels.newChannel(socket.getInputStream());
|
|
||||||
wc = Channels.newChannel(socket.getOutputStream());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
this.readChannel = rc;
|
|
||||||
this.writeChannel = wc;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
SocketAddress addr = addr0;
|
|
||||||
if (addr == null) {
|
|
||||||
try {
|
|
||||||
addr = socket.getRemoteSocketAddress();
|
|
||||||
} catch (Exception e) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.remoteAddress = addr;
|
|
||||||
this.livingCounter = livingCounter;
|
|
||||||
this.closedCounter = closedCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getRemoteAddress() {
|
|
||||||
return remoteAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketAddress getLocalAddress() {
|
|
||||||
return socket.getLocalSocketAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getReadTimeoutSeconds() {
|
|
||||||
return readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWriteTimeoutSeconds() {
|
|
||||||
return writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadTimeoutSeconds(int readTimeoutSeconds) {
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWriteTimeoutSeconds(int writeTimeoutSeconds) {
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownInput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownInput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shutdownOutput() {
|
|
||||||
try {
|
|
||||||
this.socket.shutdownOutput();
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
if (StandardSocketOptions.SO_REUSEADDR == name) {
|
|
||||||
this.socket.setReuseAddress((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_KEEPALIVE == name) {
|
|
||||||
this.socket.setKeepAlive((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.TCP_NODELAY == name) {
|
|
||||||
this.socket.setTcpNoDelay((Boolean) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_RCVBUF == name) {
|
|
||||||
this.socket.setReceiveBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (StandardSocketOptions.SO_SNDBUF == name) {
|
|
||||||
this.socket.setSendBufferSize((Integer) value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return defaultOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
for (int i = offset; i < offset + length; i++) {
|
|
||||||
rs += writeChannel.write(srcs[i]);
|
|
||||||
}
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
try {
|
|
||||||
int rs = readChannel.read(dst);
|
|
||||||
this.readtime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (handler != null) handler.failed(e, attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
try {
|
|
||||||
int rs = writeChannel.write(src);
|
|
||||||
this.writetime = System.currentTimeMillis();
|
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
this.socket.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !socket.isClosed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,366 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioAsyncConnection extends AsyncConnection {
|
|
||||||
|
|
||||||
protected int readTimeoutSeconds;
|
|
||||||
|
|
||||||
protected int writeTimeoutSeconds;
|
|
||||||
|
|
||||||
protected final Selector selector;
|
|
||||||
|
|
||||||
protected SelectionKey key;
|
|
||||||
|
|
||||||
protected final SocketChannel channel;
|
|
||||||
|
|
||||||
protected final SocketAddress remoteAddress;
|
|
||||||
|
|
||||||
ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
Object readAttachment;
|
|
||||||
|
|
||||||
CompletionHandler readHandler;
|
|
||||||
|
|
||||||
ByteBuffer writeOneBuffer;
|
|
||||||
|
|
||||||
ByteBuffer[] writeBuffers;
|
|
||||||
|
|
||||||
int writingCount;
|
|
||||||
|
|
||||||
int writeOffset;
|
|
||||||
|
|
||||||
int writeLength;
|
|
||||||
|
|
||||||
Object writeAttachment;
|
|
||||||
|
|
||||||
CompletionHandler writeHandler;
|
|
||||||
|
|
||||||
public TcpNioAsyncConnection(final SocketChannel ch, SocketAddress addr0,
|
|
||||||
final Selector selector,
|
|
||||||
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
|
||||||
this.channel = ch;
|
|
||||||
this.selector = selector;
|
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
|
||||||
this.writeTimeoutSeconds = writeTimeoutSeconds0;
|
|
||||||
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 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 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 <T> boolean setOption(SocketOption<T> name, T value) {
|
|
||||||
try {
|
|
||||||
this.channel.setOption(name, value);
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.channel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeReadHandler() {
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeReadBuffer() {
|
|
||||||
ByteBuffer buffer = this.readBuffer;
|
|
||||||
this.readBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeReadAttachment() {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
this.readAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeRead(int rs) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileRead(Throwable t) {
|
|
||||||
Object attach = this.readAttachment;
|
|
||||||
CompletionHandler handler = this.readHandler;
|
|
||||||
this.readBuffer = null;
|
|
||||||
this.readAttachment = null;
|
|
||||||
this.readHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionHandler removeWriteHandler() {
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeHandler = null;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer removeWriteOneBuffer() {
|
|
||||||
ByteBuffer buffer = this.writeOneBuffer;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer[] removeWriteBuffers() {
|
|
||||||
ByteBuffer[] buffers = this.writeBuffers;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
return buffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWritingCount() {
|
|
||||||
int rs = this.writingCount;
|
|
||||||
this.writingCount = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteOffset() {
|
|
||||||
int rs = this.writeOffset;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int removeWriteLength() {
|
|
||||||
int rs = this.writeLength;
|
|
||||||
this.writeLength = 0;
|
|
||||||
return rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object removeWriteAttachment() {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
return attach;
|
|
||||||
}
|
|
||||||
|
|
||||||
void completeWrite(int rs) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
void faileWrite(Throwable t) {
|
|
||||||
Object attach = this.writeAttachment;
|
|
||||||
CompletionHandler handler = this.writeHandler;
|
|
||||||
this.writeOneBuffer = null;
|
|
||||||
this.writeBuffers = null;
|
|
||||||
this.writeOffset = 0;
|
|
||||||
this.writeLength = 0;
|
|
||||||
this.writeAttachment = null;
|
|
||||||
this.writeHandler = null;
|
|
||||||
handler.failed(t, attach);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.readHandler != null) throw new RuntimeException("pending read");
|
|
||||||
try {
|
|
||||||
this.readBuffer = dst;
|
|
||||||
this.readAttachment = attachment;
|
|
||||||
this.readHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_READ);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_READ);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileRead(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
read(dst, attachment, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
read(dst, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeBuffers = srcs;
|
|
||||||
this.writeOffset = offset;
|
|
||||||
this.writeLength = length;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
|
||||||
if (this.writeHandler != null) throw new RuntimeException("pending write");
|
|
||||||
try {
|
|
||||||
this.writeOneBuffer = src;
|
|
||||||
this.writingCount = 0;
|
|
||||||
this.writeAttachment = attachment;
|
|
||||||
this.writeHandler = handler;
|
|
||||||
if (key == null) {
|
|
||||||
key = channel.register(selector, SelectionKey.OP_WRITE);
|
|
||||||
key.attach(this);
|
|
||||||
} else {
|
|
||||||
key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
selector.wakeup();
|
|
||||||
} catch (Exception e) {
|
|
||||||
faileWrite(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
|
||||||
CompletableFuture future = new CompletableFuture();
|
|
||||||
write(src, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
|
||||||
public void completed(Integer result, Void attachment) {
|
|
||||||
future.complete(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(Throwable exc, Void attachment) {
|
|
||||||
future.completeExceptionally(exc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
channel.close();
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isOpen() {
|
|
||||||
return channel.isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean isTCP() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,370 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.*;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import org.redkale.util.AnyValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 协议底层Server
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class TcpNioProtocolServer extends ProtocolServer {
|
|
||||||
|
|
||||||
private Selector acceptSelector;
|
|
||||||
|
|
||||||
private ServerSocketChannel serverChannel;
|
|
||||||
|
|
||||||
private NioThreadWorker[] workers;
|
|
||||||
|
|
||||||
private NioThreadWorker currWorker;
|
|
||||||
|
|
||||||
private boolean running;
|
|
||||||
|
|
||||||
public TcpNioProtocolServer(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open(AnyValue config) throws IOException {
|
|
||||||
acceptSelector = Selector.open();
|
|
||||||
this.serverChannel = ServerSocketChannel.open();
|
|
||||||
serverChannel.configureBlocking(false);
|
|
||||||
ServerSocket socket = serverChannel.socket();
|
|
||||||
socket.setReceiveBufferSize(16 * 1024);
|
|
||||||
socket.setReuseAddress(true);
|
|
||||||
|
|
||||||
final Set<SocketOption<?>> options = this.serverChannel.supportedOptions();
|
|
||||||
if (options.contains(StandardSocketOptions.TCP_NODELAY)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_REUSEADDR)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_RCVBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
if (options.contains(StandardSocketOptions.SO_SNDBUF)) {
|
|
||||||
this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(SocketAddress local, int backlog) throws IOException {
|
|
||||||
this.serverChannel.bind(local, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> Set<SocketOption<?>> supportedOptions() {
|
|
||||||
return this.serverChannel.supportedOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
|
|
||||||
this.serverChannel.setOption(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept() throws IOException {
|
|
||||||
this.serverChannel.register(acceptSelector, SelectionKey.OP_ACCEPT);
|
|
||||||
this.running = true;
|
|
||||||
this.workers = new NioThreadWorker[Runtime.getRuntime().availableProcessors()];
|
|
||||||
final CountDownLatch wkcdl = new CountDownLatch(workers.length);
|
|
||||||
for (int i = 0; i < workers.length; i++) {
|
|
||||||
workers[i] = new NioThreadWorker(wkcdl, i + 1, workers.length);
|
|
||||||
workers[i].setDaemon(true);
|
|
||||||
workers[i].start();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < workers.length - 1; i++) { //构成环形
|
|
||||||
workers[i].next = workers[i + 1];
|
|
||||||
}
|
|
||||||
workers[workers.length - 1].next = workers[0];
|
|
||||||
currWorker = workers[0];
|
|
||||||
try {
|
|
||||||
wkcdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
final CountDownLatch cdl = new CountDownLatch(1);
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
try {
|
|
||||||
acceptSelector.select();
|
|
||||||
Set<SelectionKey> selectedKeys = acceptSelector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
if (key.isAcceptable()) {
|
|
||||||
try {
|
|
||||||
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
|
|
||||||
createCounter.incrementAndGet();
|
|
||||||
livingCounter.incrementAndGet();
|
|
||||||
currWorker.addChannel(channel);
|
|
||||||
currWorker = currWorker.next;
|
|
||||||
} catch (IOException io) {
|
|
||||||
io.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
try {
|
|
||||||
cdl.await(3, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
if (!this.running) return;
|
|
||||||
serverChannel.close();
|
|
||||||
acceptSelector.close();
|
|
||||||
for (NioThreadWorker worker : workers) {
|
|
||||||
worker.interrupt();
|
|
||||||
}
|
|
||||||
this.running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NioThreadWorker extends Thread {
|
|
||||||
|
|
||||||
final Selector selector;
|
|
||||||
|
|
||||||
final CountDownLatch cdl;
|
|
||||||
|
|
||||||
private final Queue<TcpNioAsyncConnection> connected;
|
|
||||||
|
|
||||||
private final CopyOnWriteArrayList<TcpNioAsyncConnection> done;
|
|
||||||
|
|
||||||
protected volatile Thread ownerThread;
|
|
||||||
|
|
||||||
NioThreadWorker next;
|
|
||||||
|
|
||||||
public NioThreadWorker(final CountDownLatch cdl, int idx, int count) {
|
|
||||||
this.cdl = cdl;
|
|
||||||
String idxstr = "000000" + idx;
|
|
||||||
this.setName("NioThreadWorker:" + context.getServerAddress().getPort() + "-" + idxstr.substring(idxstr.length() - ("" + count).length()));
|
|
||||||
try {
|
|
||||||
this.selector = Selector.open();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
this.connected = new ArrayBlockingQueue<>(1000000);
|
|
||||||
this.done = new CopyOnWriteArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addChannel(SocketChannel channel) throws IOException {
|
|
||||||
TcpNioAsyncConnection conn = new TcpNioAsyncConnection(channel, null, selector, context.readTimeoutSeconds, context.writeTimeoutSeconds, null, null);
|
|
||||||
return connected.add(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void processConnected() {
|
|
||||||
TcpNioAsyncConnection schannel;
|
|
||||||
try {
|
|
||||||
while ((schannel = connected.poll()) != null) {
|
|
||||||
SocketChannel channel = schannel.channel;
|
|
||||||
channel.configureBlocking(false);
|
|
||||||
channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024);
|
|
||||||
channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024);
|
|
||||||
channel.register(selector, SelectionKey.OP_READ).attach(schannel);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
synchronized (done) {
|
|
||||||
for (TcpNioAsyncConnection conn : done) {
|
|
||||||
if (conn.key != null && conn.key.isValid()) {
|
|
||||||
conn.key.interestOps(SelectionKey.OP_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSameThread() {
|
|
||||||
return this.ownerThread == Thread.currentThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
this.ownerThread = Thread.currentThread();
|
|
||||||
if (cdl != null) cdl.countDown();
|
|
||||||
while (running) {
|
|
||||||
processConnected();
|
|
||||||
try {
|
|
||||||
selector.select(50);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Set<SelectionKey> selectedKeys = selector.selectedKeys();
|
|
||||||
synchronized (selectedKeys) {
|
|
||||||
Iterator<?> iter = selectedKeys.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SelectionKey key = (SelectionKey) iter.next();
|
|
||||||
iter.remove();
|
|
||||||
processKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processKey(SelectionKey key) {
|
|
||||||
if (key == null || !key.isValid()) return;
|
|
||||||
SocketChannel socket = (SocketChannel) key.channel();
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
if (!socket.isOpen()) {
|
|
||||||
if (conn == null) {
|
|
||||||
key.cancel();
|
|
||||||
} else {
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (conn == null) return;
|
|
||||||
if (key.isReadable()) {
|
|
||||||
if (conn.readHandler != null) readOP(key, socket, conn);
|
|
||||||
} else if (key.isWritable()) {
|
|
||||||
if (conn.writeHandler != null) writeOP(key, socket, conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeOP(SelectionKey key) {
|
|
||||||
if (key == null) return;
|
|
||||||
TcpNioAsyncConnection conn = (TcpNioAsyncConnection) key.attachment();
|
|
||||||
try {
|
|
||||||
if (key.isValid()) {
|
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
|
||||||
socketChannel.close();
|
|
||||||
key.attach(null);
|
|
||||||
key.cancel();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
conn.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.removeReadHandler();
|
|
||||||
final ByteBuffer buffer = conn.removeReadBuffer();
|
|
||||||
final Object attach = conn.removeReadAttachment();
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler);
|
|
||||||
if (handler == null || buffer == null) return;
|
|
||||||
try {
|
|
||||||
final int rs = socket.read(buffer);
|
|
||||||
{ //测试
|
|
||||||
buffer.flip();
|
|
||||||
byte[] bs = new byte[buffer.remaining()];
|
|
||||||
buffer.get(bs);
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------读内容: " + new String(bs));
|
|
||||||
}
|
|
||||||
//System.out.println(conn + "------readbuf:" + buffer + "-------handler:" + handler + "-------read: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeOP(SelectionKey key, SocketChannel socket, TcpNioAsyncConnection conn) {
|
|
||||||
final CompletionHandler handler = conn.writeHandler;
|
|
||||||
final ByteBuffer oneBuffer = conn.removeWriteOneBuffer();
|
|
||||||
final ByteBuffer[] buffers = conn.removeWriteBuffers();
|
|
||||||
final Object attach = conn.removeWriteAttachment();
|
|
||||||
final int writingCount = conn.removeWritingCount();
|
|
||||||
final int writeOffset = conn.removeWriteOffset();
|
|
||||||
final int writeLength = conn.removeWriteLength();
|
|
||||||
if (handler == null || (oneBuffer == null && buffers == null)) return;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler);
|
|
||||||
try {
|
|
||||||
int rs = 0;
|
|
||||||
if (oneBuffer == null) {
|
|
||||||
int offset = writeOffset;
|
|
||||||
int length = writeLength;
|
|
||||||
rs = (int) socket.write(buffers, offset, length);
|
|
||||||
boolean over = true;
|
|
||||||
int end = offset + length;
|
|
||||||
for (int i = offset; i < end; i++) {
|
|
||||||
if (buffers[i].hasRemaining()) {
|
|
||||||
over = false;
|
|
||||||
length -= i - offset;
|
|
||||||
offset = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!over) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeBuffers = buffers;
|
|
||||||
conn.writeOffset = offset;
|
|
||||||
conn.writeLength = length;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rs = socket.write(oneBuffer);
|
|
||||||
if (oneBuffer.hasRemaining()) {
|
|
||||||
conn.writingCount += rs;
|
|
||||||
conn.writeHandler = handler;
|
|
||||||
conn.writeAttachment = attach;
|
|
||||||
conn.writeOneBuffer = oneBuffer;
|
|
||||||
key.interestOps(SelectionKey.OP_READ + SelectionKey.OP_WRITE);
|
|
||||||
key.selector().wakeup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
conn.removeWriteHandler();
|
|
||||||
key.interestOps(SelectionKey.OP_READ); //OP_CONNECT
|
|
||||||
final int rs0 = rs + writingCount;
|
|
||||||
//System.out.println(conn + "------buffers:" + Arrays.toString(buffers) + "---onebuf:" + oneBuffer + "-------handler:" + handler + "-------write: " + rs);
|
|
||||||
context.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
handler.completed(rs0, attach);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
handler.failed(e, attach);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Throwable t) {
|
|
||||||
context.runAsync(() -> handler.failed(t, attach));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,41 +29,41 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class Transport {
|
public final class Transport {
|
||||||
|
|
||||||
public static final String DEFAULT_PROTOCOL = "TCP";
|
public static final String DEFAULT_PROTOCOL = "TCP";
|
||||||
|
|
||||||
protected final AtomicInteger seq = new AtomicInteger(-1);
|
protected final AtomicInteger seq = new AtomicInteger(-1);
|
||||||
|
|
||||||
protected final TransportFactory factory;
|
protected final TransportFactory factory;
|
||||||
|
|
||||||
protected final String name; //即<group>的name属性
|
protected final String name; //即<group>的name属性
|
||||||
|
|
||||||
protected final String subprotocol; //即<group>的subprotocol属性
|
protected final String subprotocol; //即<group>的subprotocol属性
|
||||||
|
|
||||||
protected final boolean tcp;
|
protected final boolean tcp;
|
||||||
|
|
||||||
protected final String protocol;
|
protected final String protocol;
|
||||||
|
|
||||||
protected final AsynchronousChannelGroup group;
|
protected final AsynchronousChannelGroup group;
|
||||||
|
|
||||||
protected final InetSocketAddress clientAddress;
|
protected final InetSocketAddress clientAddress;
|
||||||
|
|
||||||
//不可能为null
|
//不可能为null
|
||||||
protected TransportNode[] transportNodes = new TransportNode[0];
|
protected TransportNode[] transportNodes = new TransportNode[0];
|
||||||
|
|
||||||
protected final ObjectPool<ByteBuffer> bufferPool;
|
protected final ObjectPool<ByteBuffer> bufferPool;
|
||||||
|
|
||||||
protected final SSLContext sslContext;
|
protected final SSLContext sslContext;
|
||||||
|
|
||||||
//负载均衡策略
|
//负载均衡策略
|
||||||
protected final TransportStrategy strategy;
|
protected final TransportStrategy strategy;
|
||||||
|
|
||||||
protected Transport(String name, String subprotocol, TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
|
protected Transport(String name, String subprotocol, TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||||
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
|
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
|
||||||
final Collection<InetSocketAddress> addresses, final TransportStrategy strategy) {
|
final Collection<InetSocketAddress> addresses, final TransportStrategy strategy) {
|
||||||
this(name, DEFAULT_PROTOCOL, subprotocol, factory, transportBufferPool, transportChannelGroup, sslContext, clientAddress, addresses, strategy);
|
this(name, DEFAULT_PROTOCOL, subprotocol, factory, transportBufferPool, transportChannelGroup, sslContext, clientAddress, addresses, strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transport(String name, String protocol, String subprotocol,
|
protected Transport(String name, String protocol, String subprotocol,
|
||||||
final TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
|
final TransportFactory factory, final ObjectPool<ByteBuffer> transportBufferPool,
|
||||||
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
|
final AsynchronousChannelGroup transportChannelGroup, final SSLContext sslContext, final InetSocketAddress clientAddress,
|
||||||
@@ -81,7 +81,7 @@ public final class Transport {
|
|||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
updateRemoteAddresses(addresses);
|
updateRemoteAddresses(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
|
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
|
||||||
final TransportNode[] oldNodes = this.transportNodes;
|
final TransportNode[] oldNodes = this.transportNodes;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -109,7 +109,7 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean addRemoteAddresses(final InetSocketAddress addr) {
|
public final boolean addRemoteAddresses(final InetSocketAddress addr) {
|
||||||
if (addr == null) return false;
|
if (addr == null) return false;
|
||||||
if (clientAddress != null && clientAddress.equals(addr)) return false;
|
if (clientAddress != null && clientAddress.equals(addr)) return false;
|
||||||
@@ -125,7 +125,7 @@ public final class Transport {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean removeRemoteAddresses(InetSocketAddress addr) {
|
public final boolean removeRemoteAddresses(InetSocketAddress addr) {
|
||||||
if (addr == null) return false;
|
if (addr == null) return false;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -133,15 +133,15 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSubprotocol() {
|
public String getSubprotocol() {
|
||||||
return subprotocol;
|
return subprotocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
TransportNode[] nodes = this.transportNodes;
|
TransportNode[] nodes = this.transportNodes;
|
||||||
if (nodes == null) return;
|
if (nodes == null) return;
|
||||||
@@ -149,22 +149,22 @@ public final class Transport {
|
|||||||
if (node != null) node.dispose();
|
if (node != null) node.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetSocketAddress getClientAddress() {
|
public InetSocketAddress getClientAddress() {
|
||||||
return clientAddress;
|
return clientAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportNode[] getTransportNodes() {
|
public TransportNode[] getTransportNodes() {
|
||||||
return transportNodes;
|
return transportNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportNode findTransportNode(SocketAddress addr) {
|
public TransportNode findTransportNode(SocketAddress addr) {
|
||||||
for (TransportNode node : this.transportNodes) {
|
for (TransportNode node : this.transportNodes) {
|
||||||
if (node.address.equals(addr)) return node;
|
if (node.address.equals(addr)) return node;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetSocketAddress[] getRemoteAddresses() {
|
public InetSocketAddress[] getRemoteAddresses() {
|
||||||
InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length];
|
InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length];
|
||||||
for (int i = 0; i < rs.length; i++) {
|
for (int i = 0; i < rs.length; i++) {
|
||||||
@@ -172,36 +172,36 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}";
|
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteBuffer pollBuffer() {
|
public ByteBuffer pollBuffer() {
|
||||||
return bufferPool.get();
|
return bufferPool.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Supplier<ByteBuffer> getBufferSupplier() {
|
public Supplier<ByteBuffer> getBufferSupplier() {
|
||||||
return bufferPool;
|
return bufferPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerBuffer(ByteBuffer buffer) {
|
public void offerBuffer(ByteBuffer buffer) {
|
||||||
bufferPool.accept(buffer);
|
bufferPool.accept(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerBuffer(ByteBuffer... buffers) {
|
public void offerBuffer(ByteBuffer... buffers) {
|
||||||
for (ByteBuffer buffer : buffers) offerBuffer(buffer);
|
for (ByteBuffer buffer : buffers) offerBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsynchronousChannelGroup getTransportChannelGroup() {
|
public AsynchronousChannelGroup getTransportChannelGroup() {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTCP() {
|
public boolean isTCP() {
|
||||||
return tcp;
|
return tcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<AsyncConnection> pollConnection(SocketAddress addr0) {
|
public CompletableFuture<AsyncConnection> pollConnection(SocketAddress addr0) {
|
||||||
if (this.strategy != null) return strategy.pollConnection(addr0, this);
|
if (this.strategy != null) return strategy.pollConnection(addr0, this);
|
||||||
final TransportNode[] nodes = this.transportNodes;
|
final TransportNode[] nodes = this.transportNodes;
|
||||||
@@ -215,12 +215,12 @@ public final class Transport {
|
|||||||
DatagramChannel channel = DatagramChannel.open();
|
DatagramChannel channel = DatagramChannel.open();
|
||||||
channel.configureBlocking(true);
|
channel.configureBlocking(true);
|
||||||
channel.connect(udpaddr);
|
channel.connect(udpaddr);
|
||||||
return CompletableFuture.completedFuture(AsyncConnection.create(channel, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
return CompletableFuture.completedFuture(AsyncConnection.create(bufferPool, channel, sslContext, udpaddr, true, factory.readTimeoutSeconds, factory.writeTimeoutSeconds));
|
||||||
}
|
}
|
||||||
if (!rand) { //指定地址
|
if (!rand) { //指定地址
|
||||||
TransportNode node = findTransportNode(addr);
|
TransportNode node = findTransportNode(addr);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
final BlockingQueue<AsyncConnection> queue = node.conns;
|
final BlockingQueue<AsyncConnection> queue = node.conns;
|
||||||
if (!queue.isEmpty()) {
|
if (!queue.isEmpty()) {
|
||||||
@@ -233,7 +233,7 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AsyncConnection.createTCP(group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
return AsyncConnection.createTCP(bufferPool, group, sslContext, addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------随机取地址------------------------
|
//---------------------随机取地址------------------------
|
||||||
@@ -266,14 +266,14 @@ public final class Transport {
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
future.complete(asyncConn);
|
future.complete(asyncConn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, TransportNode attachment) {
|
public void failed(Throwable exc, TransportNode attachment) {
|
||||||
attachment.disabletime = now;
|
attachment.disabletime = now;
|
||||||
@@ -289,7 +289,7 @@ public final class Transport {
|
|||||||
future.complete(r);
|
future.complete(r);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
future.completeExceptionally(e);
|
future.completeExceptionally(e);
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ public final class Transport {
|
|||||||
throw new RuntimeException("transport address = " + addr, ex);
|
throw new RuntimeException("transport address = " + addr, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<AsyncConnection> pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException {
|
private CompletableFuture<AsyncConnection> pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException {
|
||||||
//从可用/不可用的地址列表中创建连接
|
//从可用/不可用的地址列表中创建连接
|
||||||
AtomicInteger count = new AtomicInteger(nodes.length);
|
AtomicInteger count = new AtomicInteger(nodes.length);
|
||||||
@@ -319,17 +319,17 @@ public final class Transport {
|
|||||||
public void completed(Void result, TransportNode attachment) {
|
public void completed(Void result, TransportNode attachment) {
|
||||||
try {
|
try {
|
||||||
attachment.disabletime = 0;
|
attachment.disabletime = 0;
|
||||||
AsyncConnection asyncConn = AsyncConnection.create(channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
AsyncConnection asyncConn = AsyncConnection.create(bufferPool, channel, attachment.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds);
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
if (!attachment.conns.offer(asyncConn)) asyncConn.dispose();
|
||||||
} else {
|
} else {
|
||||||
future.complete(asyncConn);
|
future.complete(asyncConn);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
failed(e, attachment);
|
failed(e, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, TransportNode attachment) {
|
public void failed(Throwable exc, TransportNode attachment) {
|
||||||
attachment.disabletime = now;
|
attachment.disabletime = now;
|
||||||
@@ -345,7 +345,7 @@ public final class Transport {
|
|||||||
}
|
}
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerConnection(final boolean forceClose, AsyncConnection conn) {
|
public void offerConnection(final boolean forceClose, AsyncConnection conn) {
|
||||||
if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return;
|
if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return;
|
||||||
if (!forceClose && conn.isTCP()) {
|
if (!forceClose && conn.isTCP()) {
|
||||||
@@ -359,7 +359,7 @@ public final class Transport {
|
|||||||
conn.dispose();
|
conn.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <A> void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler<Integer, A> handler) {
|
public <A> void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler<Integer, A> handler) {
|
||||||
pollConnection(addr).whenComplete((conn, ex) -> {
|
pollConnection(addr).whenComplete((conn, ex) -> {
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
@@ -367,118 +367,119 @@ public final class Transport {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
conn.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
conn.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer attachment) {
|
||||||
if (handler != null) handler.completed(result, att);
|
if (handler != null) handler.completed(result, att);
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(false, conn);
|
offerConnection(false, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer attachment) {
|
||||||
offerBuffer(buffer);
|
conn.offerBuffer(attachment);
|
||||||
offerConnection(true, conn);
|
offerConnection(true, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportNode {
|
public static class TransportNode {
|
||||||
|
|
||||||
protected InetSocketAddress address;
|
protected InetSocketAddress address;
|
||||||
|
|
||||||
protected volatile long disabletime; //不可用时的时间, 为0表示可用
|
protected volatile long disabletime; //不可用时的时间, 为0表示可用
|
||||||
|
|
||||||
protected final BlockingQueue<AsyncConnection> conns;
|
protected final BlockingQueue<AsyncConnection> conns;
|
||||||
|
|
||||||
protected final ConcurrentHashMap<String, Object> attributes = new ConcurrentHashMap<>();
|
protected final ConcurrentHashMap<String, Object> attributes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public TransportNode(int poolmaxconns, InetSocketAddress address) {
|
public TransportNode(int poolmaxconns, InetSocketAddress address) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.disabletime = 0;
|
this.disabletime = 0;
|
||||||
this.conns = new ArrayBlockingQueue<>(poolmaxconns);
|
this.conns = new ArrayBlockingQueue<>(poolmaxconns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConstructorParameters({"poolmaxconns", "address", "disabletime"})
|
@ConstructorParameters({"poolmaxconns", "address", "disabletime"})
|
||||||
public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) {
|
public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.disabletime = disabletime;
|
this.disabletime = disabletime;
|
||||||
this.conns = new LinkedBlockingQueue<>(poolmaxconns);
|
this.conns = new LinkedBlockingQueue<>(poolmaxconns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPoolmaxconns() {
|
public int getPoolmaxconns() {
|
||||||
return this.conns.remainingCapacity() + this.conns.size();
|
return this.conns.remainingCapacity() + this.conns.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T setAttribute(String name, T value) {
|
public <T> T setAttribute(String name, T value) {
|
||||||
attributes.put(name, value);
|
attributes.put(name, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getAttribute(String name) {
|
public <T> T getAttribute(String name) {
|
||||||
return (T) attributes.get(name);
|
return (T) attributes.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T removeAttribute(String name) {
|
public <T> T removeAttribute(String name) {
|
||||||
return (T) attributes.remove(name);
|
return (T) attributes.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportNode clearAttributes() {
|
public TransportNode clearAttributes() {
|
||||||
attributes.clear();
|
attributes.clear();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConcurrentHashMap<String, Object> getAttributes() {
|
public ConcurrentHashMap<String, Object> getAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttributes(ConcurrentHashMap<String, Object> map) {
|
public void setAttributes(ConcurrentHashMap<String, Object> map) {
|
||||||
attributes.clear();
|
attributes.clear();
|
||||||
if (map != null) attributes.putAll(map);
|
if (map != null) attributes.putAll(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetSocketAddress getAddress() {
|
public InetSocketAddress getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDisabletime() {
|
public long getDisabletime() {
|
||||||
return disabletime;
|
return disabletime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConvertDisabled
|
@ConvertDisabled
|
||||||
public BlockingQueue<AsyncConnection> getConns() {
|
public BlockingQueue<AsyncConnection> getConns() {
|
||||||
return conns;
|
return conns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
AsyncConnection conn;
|
AsyncConnection conn;
|
||||||
while ((conn = conns.poll()) != null) {
|
while ((conn = conns.poll()) != null) {
|
||||||
conn.dispose();
|
conn.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.address.hashCode();
|
return this.address.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
@@ -487,7 +488,7 @@ public final class Transport {
|
|||||||
final TransportNode other = (TransportNode) obj;
|
final TransportNode other = (TransportNode) obj;
|
||||||
return this.address.equals(other.address);
|
return this.address.equals(other.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return JsonConvert.root().convertTo(this);
|
return JsonConvert.root().convertTo(this);
|
||||||
|
|||||||
@@ -393,33 +393,34 @@ public class TransportFactory {
|
|||||||
final BlockingQueue<AsyncConnection> localqueue = queue;
|
final BlockingQueue<AsyncConnection> localqueue = queue;
|
||||||
localconn.write(sendBuffer, sendBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
localconn.write(sendBuffer, sendBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer buffer) {
|
public void completed(Integer result, ByteBuffer wbuffer) {
|
||||||
if (buffer.hasRemaining()) {
|
if (wbuffer.hasRemaining()) {
|
||||||
localconn.write(buffer, buffer, this);
|
localconn.write(wbuffer, wbuffer, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ByteBuffer pongBuffer = bufferPool.get();
|
localconn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
localconn.read(pongBuffer, pongBuffer, new CompletionHandler<Integer, ByteBuffer>() {
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, ByteBuffer attachment) {
|
public void completed(Integer result, ByteBuffer pongBuffer) {
|
||||||
if (counter > 3) {
|
if (counter > 3) {
|
||||||
bufferPool.accept(attachment);
|
localconn.offerBuffer(pongBuffer);
|
||||||
localconn.dispose();
|
localconn.dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pongLength > 0 && attachment.position() < pongLength) {
|
if (pongLength > 0 && pongBuffer.position() < pongLength) {
|
||||||
counter++;
|
counter++;
|
||||||
localconn.read(pongBuffer, pongBuffer, this);
|
localconn.setReadBuffer(pongBuffer);
|
||||||
|
localconn.read(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bufferPool.accept(attachment);
|
localconn.offerBuffer(pongBuffer);
|
||||||
localqueue.offer(localconn);
|
localqueue.offer(localconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment) {
|
public void failed(Throwable exc, ByteBuffer pongBuffer) {
|
||||||
|
localconn.offerBuffer(pongBuffer);
|
||||||
localconn.dispose();
|
localconn.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import java.nio.channels.*;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.*;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -32,9 +34,11 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
|
|
||||||
private final boolean client;
|
private final boolean client;
|
||||||
|
|
||||||
public UdpBioAsyncConnection(final DatagramChannel ch, SocketAddress addr0,
|
public UdpBioAsyncConnection(Supplier<ByteBuffer> bufferSupplier, Consumer<ByteBuffer> bufferConsumer,
|
||||||
final boolean client0, final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
final DatagramChannel ch, final SSLContext sslContext, SocketAddress addr0, final boolean client0,
|
||||||
|
final int readTimeoutSeconds0, final int writeTimeoutSeconds0,
|
||||||
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
final AtomicLong livingCounter, final AtomicLong closedCounter) {
|
||||||
|
super(bufferSupplier, bufferConsumer, sslContext);
|
||||||
this.channel = ch;
|
this.channel = ch;
|
||||||
this.client = client0;
|
this.client = client0;
|
||||||
this.readTimeoutSeconds = readTimeoutSeconds0;
|
this.readTimeoutSeconds = readTimeoutSeconds0;
|
||||||
@@ -127,30 +131,27 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
|
ByteBuffer dst = pollReadBuffer();
|
||||||
try {
|
try {
|
||||||
int rs = channel.read(dst);
|
int rs = channel.read(dst);
|
||||||
this.readtime = System.currentTimeMillis();
|
this.readtime = System.currentTimeMillis();
|
||||||
if (handler != null) handler.completed(rs, attachment);
|
if (handler != null) handler.completed(rs, dst);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (handler != null) handler.failed(e, attachment);
|
if (handler != null) handler.failed(e, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <A> void read(ByteBuffer dst, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public void read(long timeout, TimeUnit unit, CompletionHandler<Integer, ByteBuffer> handler) {
|
||||||
read(dst, attachment, handler);
|
read(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<Integer> read(ByteBuffer dst) {
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
try {
|
int rs = channel.read(dst);
|
||||||
int rs = channel.read(dst);
|
this.readtime = System.currentTimeMillis();
|
||||||
this.readtime = System.currentTimeMillis();
|
return rs;
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,14 +166,10 @@ public class UdpBioAsyncConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<Integer> write(ByteBuffer src) {
|
public int write(ByteBuffer src) throws IOException {
|
||||||
try {
|
int rs = channel.send(src, remoteAddress);
|
||||||
int rs = channel.send(src, remoteAddress);
|
this.writetime = System.currentTimeMillis();
|
||||||
this.writetime = System.currentTimeMillis();
|
return rs;
|
||||||
return CompletableFuture.completedFuture(rs);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ public class UdpBioProtocolServer extends ProtocolServer {
|
|||||||
try {
|
try {
|
||||||
SocketAddress address = serchannel.receive(buffer);
|
SocketAddress address = serchannel.receive(buffer);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
AsyncConnection conn = new UdpBioAsyncConnection(serchannel, address, false, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
AsyncConnection conn = new UdpBioAsyncConnection(context.getBufferSupplier(), context.getBufferConsumer(), serchannel,
|
||||||
|
context.getSSLContext(), address, false, readTimeoutSeconds, writeTimeoutSeconds, null, null);
|
||||||
context.runAsync(new PrepareRunner(context, conn, buffer, null));
|
context.runAsync(new PrepareRunner(context, conn, buffer, null));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.offerBuffer(buffer);
|
context.offerBuffer(buffer);
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ class WebSocketRunner implements Runnable {
|
|||||||
|
|
||||||
protected final HttpContext context;
|
protected final HttpContext context;
|
||||||
|
|
||||||
private ByteBuffer readBuffer;
|
|
||||||
|
|
||||||
volatile boolean closed = false;
|
volatile boolean closed = false;
|
||||||
|
|
||||||
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
|
private final BiConsumer<WebSocket, Object> restMessageConsumer; //主要供RestWebSocket使用
|
||||||
@@ -50,7 +48,6 @@ class WebSocketRunner implements Runnable {
|
|||||||
this.webSocket = webSocket;
|
this.webSocket = webSocket;
|
||||||
this.restMessageConsumer = messageConsumer;
|
this.restMessageConsumer = messageConsumer;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.readBuffer = context.pollBuffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -61,7 +58,7 @@ class WebSocketRunner implements Runnable {
|
|||||||
channel.setReadTimeoutSeconds(300); //读取超时5分钟
|
channel.setReadTimeoutSeconds(300); //读取超时5分钟
|
||||||
if (channel.isOpen()) {
|
if (channel.isOpen()) {
|
||||||
final int wsmaxbody = webSocket._engine.wsmaxbody;
|
final int wsmaxbody = webSocket._engine.wsmaxbody;
|
||||||
channel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {
|
channel.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
|
|
||||||
//尚未解析完的数据包
|
//尚未解析完的数据包
|
||||||
private WebSocketPacket unfinishPacket;
|
private WebSocketPacket unfinishPacket;
|
||||||
@@ -72,31 +69,27 @@ class WebSocketRunner implements Runnable {
|
|||||||
private final SimpleEntry<String, byte[]> halfBytes = new SimpleEntry("", null);
|
private final SimpleEntry<String, byte[]> halfBytes = new SimpleEntry("", null);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment1) {
|
public void completed(Integer count, ByteBuffer readBuffer) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid=" + webSocket.getUserid() + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner(userid=" + webSocket.getUserid() + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
||||||
closeRunner(CLOSECODE_ILLPACKET, "read buffer count is " + count);
|
closeRunner(CLOSECODE_ILLPACKET, "read buffer count is " + count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ByteBuffer readBuf = readBuffer;
|
|
||||||
if (readBuf == null) return; //关闭后readBuffer为null
|
|
||||||
lastReadTime = System.currentTimeMillis();
|
lastReadTime = System.currentTimeMillis();
|
||||||
readBuf.flip();
|
readBuffer.flip();
|
||||||
|
|
||||||
WebSocketPacket onePacket = null;
|
WebSocketPacket onePacket = null;
|
||||||
if (unfinishPacket != null) {
|
if (unfinishPacket != null) {
|
||||||
if (unfinishPacket.receiveBody(webSocket, readBuf)) { //已经接收完毕
|
if (unfinishPacket.receiveBody(webSocket, readBuffer)) { //已经接收完毕
|
||||||
onePacket = unfinishPacket;
|
onePacket = unfinishPacket;
|
||||||
unfinishPacket = null;
|
unfinishPacket = null;
|
||||||
for (ByteBuffer b : exBuffers) {
|
for (ByteBuffer b : exBuffers) {
|
||||||
context.offerBuffer(b);
|
context.offerBuffer(b);
|
||||||
}
|
}
|
||||||
exBuffers.clear();
|
exBuffers.clear();
|
||||||
} else { //需要继续接收
|
} else { //需要继续接收, 此处不能回收readBuffer
|
||||||
readBuf = context.pollBuffer();
|
channel.read(this);
|
||||||
readBuffer = readBuf;
|
|
||||||
channel.read(readBuf, null, this);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,37 +98,36 @@ class WebSocketRunner implements Runnable {
|
|||||||
if (onePacket != null) packets.add(onePacket);
|
if (onePacket != null) packets.add(onePacket);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), webSocket, wsmaxbody, halfBytes, readBuf);
|
WebSocketPacket packet = new WebSocketPacket().decode(context.getLogger(), webSocket, wsmaxbody, halfBytes, readBuffer);
|
||||||
if (packet == WebSocketPacket.NONE) break; //解析完毕但是buffer有多余字节
|
if (packet == WebSocketPacket.NONE) break; //解析完毕但是buffer有多余字节
|
||||||
if (packet != null && !packet.isReceiveFinished()) {
|
if (packet != null && !packet.isReceiveFinished()) {
|
||||||
unfinishPacket = packet;
|
unfinishPacket = packet;
|
||||||
if (readBuf.hasRemaining()) {
|
if (readBuffer.hasRemaining()) {
|
||||||
exBuffers.add(readBuf);
|
exBuffers.add(readBuffer);
|
||||||
readBuf = context.pollBuffer();
|
|
||||||
readBuffer = readBuf;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
packets.add(packet);
|
packets.add(packet);
|
||||||
if (packet == null || !readBuf.hasRemaining()) break;
|
if (packet == null || !readBuffer.hasRemaining()) break;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
context.getLogger().log(Level.SEVERE, "WebSocket parse message error", e);
|
context.getLogger().log(Level.SEVERE, "WebSocket parse message error", e);
|
||||||
webSocket.onOccurException(e, null);
|
webSocket.onOccurException(e, null);
|
||||||
}
|
}
|
||||||
//继续监听消息
|
//继续监听消息
|
||||||
readBuf.clear();
|
readBuffer.clear();
|
||||||
if (halfBytes.getValue() != null) {
|
if (halfBytes.getValue() != null) {
|
||||||
readBuf.put(halfBytes.getValue());
|
readBuffer.put(halfBytes.getValue());
|
||||||
halfBytes.setValue(null);
|
halfBytes.setValue(null);
|
||||||
}
|
}
|
||||||
channel.read(readBuf, null, this);
|
channel.setReadBuffer(readBuffer);
|
||||||
|
channel.read(this);
|
||||||
|
|
||||||
//消息处理
|
//消息处理
|
||||||
for (final WebSocketPacket packet : packets) {
|
for (final WebSocketPacket packet : packets) {
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner abort on decode WebSocketPacket, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner abort on decode WebSocketPacket, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds");
|
||||||
failed(null, attachment1);
|
failed(null, readBuffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +189,7 @@ class WebSocketRunner implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer attachment2) {
|
||||||
if (exc != null) {
|
if (exc != null) {
|
||||||
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
if (debug) context.getLogger().log(Level.FINEST, "WebSocketRunner read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc);
|
||||||
closeRunner(CLOSECODE_WSEXCEPTION, "read websocket-packet failed");
|
closeRunner(CLOSECODE_WSEXCEPTION, "read websocket-packet failed");
|
||||||
@@ -302,8 +294,6 @@ class WebSocketRunner implements Runnable {
|
|||||||
if (closed) return null;
|
if (closed) return null;
|
||||||
closed = true;
|
closed = true;
|
||||||
channel.dispose();
|
channel.dispose();
|
||||||
context.offerBuffer(readBuffer);
|
|
||||||
readBuffer = null;
|
|
||||||
CompletableFuture<Void> future = engine.removeThenClose(webSocket);
|
CompletableFuture<Void> future = engine.removeThenClose(webSocket);
|
||||||
webSocket.onClose(code, reason);
|
webSocket.onClose(code, reason);
|
||||||
return future;
|
return future;
|
||||||
|
|||||||
@@ -370,7 +370,6 @@ public final class SncpClient {
|
|||||||
final ByteBuffer[] sendBuffers = writer.toBuffers();
|
final ByteBuffer[] sendBuffers = writer.toBuffers();
|
||||||
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
|
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
|
||||||
|
|
||||||
final ByteBuffer buffer = transport.pollBuffer();
|
|
||||||
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
|
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -393,25 +392,25 @@ public final class SncpClient {
|
|||||||
conn.write(newattachs, newattachs, this);
|
conn.write(newattachs, newattachs, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//----------------------- 读取返回结果 -------------------------------------
|
//----------------------- 读取返回结果 -------------------------------------
|
||||||
buffer.clear();
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
conn.read(buffer, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
|
|
||||||
private byte[] body;
|
private byte[] body;
|
||||||
|
|
||||||
private int received;
|
private int received;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer count, Void attachment2) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
try {
|
try {
|
||||||
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
||||||
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
|
||||||
transport.offerBuffer(buffer);
|
conn.offerBuffer(buffer);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (received < 1 && buffer.limit() < buffer.remaining() + HEADER_SIZE) { //header都没读全
|
if (received < 1 && buffer.limit() < buffer.remaining() + HEADER_SIZE) { //header都没读全
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
@@ -421,8 +420,10 @@ public final class SncpClient {
|
|||||||
buffer.get(body, offset, Math.min(buffer.remaining(), this.body.length - offset));
|
buffer.get(body, offset, Math.min(buffer.remaining(), this.body.length - offset));
|
||||||
if (this.received < this.body.length) {// 数据仍然不全,需要继续读取
|
if (this.received < this.body.length) {// 数据仍然不全,需要继续读取
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
} else {
|
} else {
|
||||||
|
conn.offerBuffer(buffer);
|
||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -441,10 +442,12 @@ public final class SncpClient {
|
|||||||
this.received = buffer.remaining();
|
this.received = buffer.remaining();
|
||||||
buffer.get(body, 0, this.received);
|
buffer.get(body, 0, this.received);
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, attachment2, this);
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(this);
|
||||||
} else {
|
} else {
|
||||||
this.body = new byte[respBodyLength];
|
this.body = new byte[respBodyLength];
|
||||||
buffer.get(body, 0, respBodyLength);
|
buffer.get(body, 0, respBodyLength);
|
||||||
|
conn.offerBuffer(buffer);
|
||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -461,7 +464,6 @@ public final class SncpClient {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void success() {
|
public void success() {
|
||||||
future.complete(this.body);
|
future.complete(this.body);
|
||||||
transport.offerBuffer(buffer);
|
|
||||||
transport.offerConnection(false, conn);
|
transport.offerConnection(false, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
@@ -484,9 +486,9 @@ public final class SncpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer attachment2) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
||||||
transport.offerBuffer(buffer);
|
conn.offerBuffer(attachment2);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
@@ -500,7 +502,6 @@ public final class SncpClient {
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
||||||
transport.offerBuffer(buffer);
|
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return AsyncConnection.createTCP(group, this.servaddr, this.readTimeoutSeconds, this.writeTimeoutSeconds).thenCompose(conn -> {
|
return AsyncConnection.createTCP(bufferPool, group, this.servaddr, this.readTimeoutSeconds, this.writeTimeoutSeconds).thenCompose(conn -> {
|
||||||
conn.beforeCloseListener((c) -> {
|
conn.beforeCloseListener((c) -> {
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
closeCounter.incrementAndGet();
|
closeCounter.incrementAndGet();
|
||||||
@@ -143,12 +143,11 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
|||||||
final ByteBuffer buffer = reqConnectBuffer(conn);
|
final ByteBuffer buffer = reqConnectBuffer(conn);
|
||||||
|
|
||||||
if (buffer == null) {
|
if (buffer == null) {
|
||||||
final ByteBuffer rbuffer = bufferPool.get();
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
conn.read(rbuffer, null, new CompletionHandler<Integer, Void>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, Void attachment2) {
|
public void completed(Integer result, ByteBuffer rbuffer) {
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
failed(new SQLException("Read Buffer Error"), attachment2);
|
failed(new SQLException("Read Buffer Error"), rbuffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rbuffer.flip();
|
rbuffer.flip();
|
||||||
@@ -156,8 +155,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer rbuffer) {
|
||||||
bufferPool.accept(rbuffer);
|
conn.offerBuffer(rbuffer);
|
||||||
future.completeExceptionally(exc);
|
future.completeExceptionally(exc);
|
||||||
conn.dispose();
|
conn.dispose();
|
||||||
}
|
}
|
||||||
@@ -175,11 +174,12 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
conn.read(buffer, null, new CompletionHandler<Integer, Void>() {
|
conn.setReadBuffer(buffer);
|
||||||
|
conn.read(new CompletionHandler<Integer, ByteBuffer>() {
|
||||||
@Override
|
@Override
|
||||||
public void completed(Integer result, Void attachment2) {
|
public void completed(Integer result, ByteBuffer rbuffer) {
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
failed(new SQLException("Read Buffer Error"), attachment2);
|
failed(new SQLException("Read Buffer Error"), rbuffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
@@ -187,8 +187,8 @@ public abstract class PoolTcpSource extends PoolSource<AsyncConnection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, Void attachment2) {
|
public void failed(Throwable exc, ByteBuffer rbuffer) {
|
||||||
bufferPool.accept(buffer);
|
conn.offerBuffer(rbuffer);
|
||||||
future.completeExceptionally(exc);
|
future.completeExceptionally(exc);
|
||||||
conn.dispose();
|
conn.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user