AsyncConnection优化
This commit is contained in:
@@ -352,38 +352,35 @@ public abstract class AsyncConnection implements Channel, AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void write(byte[] bytes, CompletionHandler<Integer, Void> handler) {
|
public final void write(byte[] bytes, CompletionHandler<Integer, Void> handler) {
|
||||||
write(bytes, 0, bytes.length, null, 0, 0, null, null, handler);
|
write(bytes, 0, bytes.length, null, 0, 0, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void write(ByteTuple array, CompletionHandler<Integer, Void> handler) {
|
public final void write(ByteTuple array, CompletionHandler<Integer, Void> handler) {
|
||||||
write(array.content(), array.offset(), array.length(), null, 0, 0, null, null, handler);
|
write(array.content(), array.offset(), array.length(), null, 0, 0, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final <A> void write(ByteTuple array, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
public final <A> void write(ByteTuple array, A attachment, CompletionHandler<Integer, ? super A> handler) {
|
||||||
write(array.content(), array.offset(), array.length(), null, 0, 0, null, null, attachment, handler);
|
write(array.content(), array.offset(), array.length(), null, 0, 0, attachment, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void write(byte[] bytes, int offset, int length, CompletionHandler<Integer, Void> handler) {
|
public final void write(byte[] bytes, int offset, int length, CompletionHandler<Integer, Void> handler) {
|
||||||
write(bytes, offset, length, null, 0, 0, null, null, handler);
|
write(bytes, offset, length, null, 0, 0, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void write(ByteTuple header, ByteTuple body, CompletionHandler<Integer, Void> handler) {
|
public final void write(ByteTuple header, ByteTuple body, CompletionHandler<Integer, Void> handler) {
|
||||||
write(header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length(), null, null, handler);
|
write(header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length(), handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler<Integer, Void> handler) {
|
public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, CompletionHandler<Integer, Void> handler) {
|
||||||
write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, null, handler);
|
write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, null, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, Object handlerAttachment, CompletionHandler handler) {
|
public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Object handlerAttachment, CompletionHandler handler) {
|
||||||
final ByteBuffer buffer = sslEngine == null ? pollWriteBuffer() : pollWriteSSLBuffer();
|
final ByteBuffer buffer = sslEngine == null ? pollWriteBuffer() : pollWriteSSLBuffer();
|
||||||
if (buffer.remaining() >= headerLength + bodyLength) {
|
if (buffer.remaining() >= headerLength + bodyLength) {
|
||||||
buffer.put(headerContent, headerOffset, headerLength);
|
buffer.put(headerContent, headerOffset, headerLength);
|
||||||
if (bodyLength > 0) {
|
if (bodyLength > 0) {
|
||||||
buffer.put(bodyContent, bodyOffset, bodyLength);
|
buffer.put(bodyContent, bodyOffset, bodyLength);
|
||||||
if (bodyCallback != null) {
|
|
||||||
bodyCallback.accept(bodyAttachment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
CompletionHandler<Integer, Object> newHandler = new CompletionHandler<Integer, Object>() {
|
CompletionHandler<Integer, Object> newHandler = new CompletionHandler<Integer, Object>() {
|
||||||
@@ -405,9 +402,6 @@ public abstract class AsyncConnection implements Channel, AutoCloseable {
|
|||||||
writer.put(headerContent, headerOffset, headerLength);
|
writer.put(headerContent, headerOffset, headerLength);
|
||||||
if (bodyLength > 0) {
|
if (bodyLength > 0) {
|
||||||
writer.put(bodyContent, bodyOffset, bodyLength);
|
writer.put(bodyContent, bodyOffset, bodyLength);
|
||||||
if (bodyCallback != null) {
|
|
||||||
bodyCallback.accept(bodyAttachment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final ByteBuffer[] buffers = writer.toBuffers();
|
final ByteBuffer[] buffers = writer.toBuffers();
|
||||||
CompletionHandler<Integer, Object> newHandler = new CompletionHandler<Integer, Object>() {
|
CompletionHandler<Integer, Object> newHandler = new CompletionHandler<Integer, Object>() {
|
||||||
@@ -486,11 +480,11 @@ public abstract class AsyncConnection implements Channel, AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void writeInIOThread(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler<Integer, Void> handler) {
|
public final void writeInIOThread(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, CompletionHandler<Integer, Void> handler) {
|
||||||
if (inCurrWriteThread()) {
|
if (inCurrWriteThread()) {
|
||||||
write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, handler);
|
write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, handler);
|
||||||
} else {
|
} else {
|
||||||
executeWrite(() -> write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, handler));
|
executeWrite(() -> write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, handler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ public class AsyncIOThread extends WorkThread {
|
|||||||
conn.doConnect();
|
conn.doConnect();
|
||||||
} else if (conn.writeCompletionHandler != null && key.isWritable()) {
|
} else if (conn.writeCompletionHandler != null && key.isWritable()) {
|
||||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
||||||
conn.doWrite(true);
|
conn.doWrite();
|
||||||
} else if (conn.readCompletionHandler != null && key.isReadable()) {
|
} else if (conn.readCompletionHandler != null && key.isReadable()) {
|
||||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
|
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
|
||||||
conn.doRead(true);
|
conn.doRead(true);
|
||||||
@@ -195,7 +195,7 @@ public class AsyncIOThread extends WorkThread {
|
|||||||
conn.doRead(true);
|
conn.doRead(true);
|
||||||
} else if (conn.writeCompletionHandler != null && key.isWritable()) {
|
} else if (conn.writeCompletionHandler != null && key.isWritable()) {
|
||||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
||||||
conn.doWrite(true);
|
conn.doWrite();
|
||||||
} else if (key.isConnectable()) {
|
} else if (key.isConnectable()) {
|
||||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
|
key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
|
||||||
conn.doConnect();
|
conn.doConnect();
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
|
|
||||||
protected int writeByteTuple2Length;
|
protected int writeByteTuple2Length;
|
||||||
|
|
||||||
protected Consumer writeByteTuple2Callback;
|
|
||||||
|
|
||||||
protected Object writeByteTuple2Attachment;
|
|
||||||
|
|
||||||
//写操作, 二选一,要么writeByteBuffer有值,要么writeByteBuffers、writeOffset、writeLength有值
|
//写操作, 二选一,要么writeByteBuffer有值,要么writeByteBuffers、writeOffset、writeLength有值
|
||||||
protected ByteBuffer writeByteBuffer;
|
protected ByteBuffer writeByteBuffer;
|
||||||
|
|
||||||
@@ -188,11 +184,10 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] headerContent, int headerOffset, int headerLength,
|
public void write(byte[] headerContent, int headerOffset, int headerLength,
|
||||||
byte[] bodyContent, int bodyOffset, int bodyLength,
|
byte[] bodyContent, int bodyOffset, int bodyLength, CompletionHandler<Integer, Void> handler) {
|
||||||
Consumer bodyCallback, Object bodyAttachment, CompletionHandler<Integer, Void> handler) {
|
|
||||||
|
|
||||||
if (sslEngine != null) {
|
if (sslEngine != null) {
|
||||||
super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, handler);
|
super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, handler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Objects.requireNonNull(headerContent);
|
Objects.requireNonNull(headerContent);
|
||||||
@@ -212,8 +207,6 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
this.writeByteTuple2Array = bodyContent;
|
this.writeByteTuple2Array = bodyContent;
|
||||||
this.writeByteTuple2Offset = bodyOffset;
|
this.writeByteTuple2Offset = bodyOffset;
|
||||||
this.writeByteTuple2Length = bodyLength;
|
this.writeByteTuple2Length = bodyLength;
|
||||||
this.writeByteTuple2Callback = bodyCallback;
|
|
||||||
this.writeByteTuple2Attachment = bodyAttachment;
|
|
||||||
this.writeAttachment = null;
|
this.writeAttachment = null;
|
||||||
if (this.writeTimeoutSeconds > 0) {
|
if (this.writeTimeoutSeconds > 0) {
|
||||||
AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler;
|
AsyncNioCompletionHandler newHandler = this.writeTimeoutCompletionHandler;
|
||||||
@@ -225,7 +218,7 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null);
|
newHandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null);
|
||||||
this.writeCompletionHandler = newHandler;
|
this.writeCompletionHandler = newHandler;
|
||||||
}
|
}
|
||||||
doWrite(true); //如果不是true,则bodyCallback的执行可能会切换线程
|
doWrite(); //如果不是true,则bodyCallback的执行可能会切换线程
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -251,7 +244,7 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
} else {
|
} else {
|
||||||
this.writeCompletionHandler = (CompletionHandler) handler;
|
this.writeCompletionHandler = (CompletionHandler) handler;
|
||||||
}
|
}
|
||||||
doWrite(true);
|
doWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -279,7 +272,7 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
} else {
|
} else {
|
||||||
this.writeCompletionHandler = (CompletionHandler) handler;
|
this.writeCompletionHandler = (CompletionHandler) handler;
|
||||||
}
|
}
|
||||||
doWrite(true);
|
doWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doRead(boolean direct) {
|
public void doRead(boolean direct) {
|
||||||
@@ -315,105 +308,94 @@ abstract class AsyncNioConnection extends AsyncConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doWrite(boolean direct) {
|
public void doWrite() {
|
||||||
try {
|
try {
|
||||||
this.writeTime = System.currentTimeMillis();
|
this.writeTime = System.currentTimeMillis();
|
||||||
int totalCount = 0;
|
int totalCount = 0;
|
||||||
boolean hasRemain = true;
|
boolean hasRemain = true;
|
||||||
boolean writeCompleted = true;
|
boolean writeCompleted = true;
|
||||||
if (direct) {
|
|
||||||
int batchOffset = writeOffset;
|
|
||||||
int batchLength = writeLength;
|
|
||||||
while (hasRemain) { //必须要将buffer写完为止
|
|
||||||
if (writeByteTuple1Array != null) {
|
|
||||||
final ByteBuffer buffer = pollWriteBuffer();
|
|
||||||
if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) {
|
|
||||||
buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length);
|
|
||||||
if (writeByteTuple2Length > 0) {
|
|
||||||
buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length);
|
|
||||||
if (writeByteTuple2Callback != null) {
|
|
||||||
writeByteTuple2Callback.accept(writeByteTuple2Attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.flip();
|
|
||||||
writeByteBuffer = buffer;
|
|
||||||
writeByteTuple1Array = null;
|
|
||||||
writeByteTuple1Offset = 0;
|
|
||||||
writeByteTuple1Length = 0;
|
|
||||||
writeByteTuple2Array = null;
|
|
||||||
writeByteTuple2Offset = 0;
|
|
||||||
writeByteTuple2Length = 0;
|
|
||||||
writeByteTuple2Callback = null;
|
|
||||||
writeByteTuple2Attachment = null;
|
|
||||||
} else {
|
|
||||||
ByteBufferWriter writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer);
|
|
||||||
writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length);
|
|
||||||
if (writeByteTuple2Length > 0) {
|
|
||||||
writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length);
|
|
||||||
if (writeByteTuple2Callback != null) {
|
|
||||||
writeByteTuple2Callback.accept(writeByteTuple2Attachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final ByteBuffer[] buffers = writer.toBuffers();
|
|
||||||
writeByteBuffers = buffers;
|
|
||||||
writeOffset = 0;
|
|
||||||
writeLength = buffers.length;
|
|
||||||
batchOffset = writeOffset;
|
|
||||||
batchLength = writeLength;
|
|
||||||
writeByteTuple1Array = null;
|
|
||||||
writeByteTuple1Offset = 0;
|
|
||||||
writeByteTuple1Length = 0;
|
|
||||||
writeByteTuple2Array = null;
|
|
||||||
writeByteTuple2Offset = 0;
|
|
||||||
writeByteTuple2Length = 0;
|
|
||||||
writeByteTuple2Callback = null;
|
|
||||||
writeByteTuple2Attachment = null;
|
|
||||||
}
|
|
||||||
if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) {
|
|
||||||
if (writeByteBuffer == null) {
|
|
||||||
this.writeTimeoutCompletionHandler.buffers(writeByteBuffers);
|
|
||||||
} else {
|
|
||||||
this.writeTimeoutCompletionHandler.buffer(writeByteBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int writeCount;
|
|
||||||
if (writeByteBuffer != null) {
|
|
||||||
writeCount = implWrite(writeByteBuffer);
|
|
||||||
hasRemain = writeByteBuffer.hasRemaining();
|
|
||||||
} else {
|
|
||||||
writeCount = implWrite(writeByteBuffers, batchOffset, batchLength);
|
|
||||||
boolean remain = false;
|
|
||||||
for (int i = 0; i < batchLength; i++) {
|
|
||||||
if (writeByteBuffers[batchOffset + i].hasRemaining()) {
|
|
||||||
remain = true;
|
|
||||||
batchOffset += i;
|
|
||||||
batchLength -= i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hasRemain = remain;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeCount == 0) {
|
int batchOffset = writeOffset;
|
||||||
if (hasRemain) {
|
int batchLength = writeLength;
|
||||||
//writeCompleted = false;
|
while (hasRemain) { //必须要将buffer写完为止
|
||||||
//writeTotal = totalCount;
|
if (writeByteTuple1Array != null) {
|
||||||
continue; //要全部输出完才返回
|
final ByteBuffer buffer = pollWriteBuffer();
|
||||||
|
if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) {
|
||||||
|
buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length);
|
||||||
|
if (writeByteTuple2Length > 0) {
|
||||||
|
buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length);
|
||||||
}
|
}
|
||||||
break;
|
buffer.flip();
|
||||||
} else if (writeCount < 0) {
|
writeByteBuffer = buffer;
|
||||||
if (totalCount == 0) {
|
writeByteTuple1Array = null;
|
||||||
totalCount = writeCount;
|
writeByteTuple1Offset = 0;
|
||||||
}
|
writeByteTuple1Length = 0;
|
||||||
break;
|
writeByteTuple2Array = null;
|
||||||
|
writeByteTuple2Offset = 0;
|
||||||
|
writeByteTuple2Length = 0;
|
||||||
} else {
|
} else {
|
||||||
totalCount += writeCount;
|
ByteBufferWriter writer = ByteBufferWriter.create(getWriteBufferSupplier(), buffer);
|
||||||
|
writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length);
|
||||||
|
if (writeByteTuple2Length > 0) {
|
||||||
|
writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length);
|
||||||
|
}
|
||||||
|
final ByteBuffer[] buffers = writer.toBuffers();
|
||||||
|
writeByteBuffers = buffers;
|
||||||
|
writeOffset = 0;
|
||||||
|
writeLength = buffers.length;
|
||||||
|
batchOffset = writeOffset;
|
||||||
|
batchLength = writeLength;
|
||||||
|
writeByteTuple1Array = null;
|
||||||
|
writeByteTuple1Offset = 0;
|
||||||
|
writeByteTuple1Length = 0;
|
||||||
|
writeByteTuple2Array = null;
|
||||||
|
writeByteTuple2Offset = 0;
|
||||||
|
writeByteTuple2Length = 0;
|
||||||
}
|
}
|
||||||
if (!hasRemain) {
|
if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) {
|
||||||
break;
|
if (writeByteBuffer == null) {
|
||||||
|
this.writeTimeoutCompletionHandler.buffers(writeByteBuffers);
|
||||||
|
} else {
|
||||||
|
this.writeTimeoutCompletionHandler.buffer(writeByteBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int writeCount;
|
||||||
|
if (writeByteBuffer != null) {
|
||||||
|
writeCount = implWrite(writeByteBuffer);
|
||||||
|
hasRemain = writeByteBuffer.hasRemaining();
|
||||||
|
} else {
|
||||||
|
writeCount = implWrite(writeByteBuffers, batchOffset, batchLength);
|
||||||
|
boolean remain = false;
|
||||||
|
for (int i = 0; i < batchLength; i++) {
|
||||||
|
if (writeByteBuffers[batchOffset + i].hasRemaining()) {
|
||||||
|
remain = true;
|
||||||
|
batchOffset += i;
|
||||||
|
batchLength -= i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasRemain = remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeCount == 0) {
|
||||||
|
if (hasRemain) {
|
||||||
|
//writeCompleted = false;
|
||||||
|
//writeTotal = totalCount;
|
||||||
|
continue; //要全部输出完才返回
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (writeCount < 0) {
|
||||||
|
if (totalCount == 0) {
|
||||||
|
totalCount = writeCount;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
totalCount += writeCount;
|
||||||
|
}
|
||||||
|
if (!hasRemain) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeCompleted && (totalCount != 0 || !hasRemain)) {
|
if (writeCompleted && (totalCount != 0 || !hasRemain)) {
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <A> void finish(boolean kill, final byte[] bs1, int offset1, int length1, final byte[] bs2, int offset2, int length2, Consumer<A> callback, A attachment) {
|
public <A> void finish(boolean kill, final byte[] bs1, int offset1, int length1, final byte[] bs2, int offset2, int length2) {
|
||||||
if (kill) {
|
if (kill) {
|
||||||
refuseAlive();
|
refuseAlive();
|
||||||
}
|
}
|
||||||
@@ -384,7 +384,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
|
|||||||
this.channel.appendPipeline(request.pipelineIndex, request.pipelineCount, bs1, offset1, length1, bs2, offset2, length2);
|
this.channel.appendPipeline(request.pipelineIndex, request.pipelineCount, bs1, offset1, length1, bs2, offset2, length2);
|
||||||
this.channel.writePipelineInIOThread(this.finishBytesIOThreadHandler);
|
this.channel.writePipelineInIOThread(this.finishBytesIOThreadHandler);
|
||||||
} else {
|
} else {
|
||||||
this.channel.writeInIOThread(bs1, offset1, length1, bs2, offset2, length2, callback, attachment, finishBytesIOThreadHandler);
|
this.channel.writeInIOThread(bs1, offset1, length1, bs2, offset2, length2, finishBytesIOThreadHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user