Commit first round of classes to support nio2/async channel api. Still work in progress.. See #396
This commit is contained in:
parent
fa63b89fc3
commit
18aaae3c2e
5
pom.xml
5
pom.xml
@ -281,6 +281,11 @@
|
|||||||
<ignore>java.nio.channels.MembershipKey</ignore>
|
<ignore>java.nio.channels.MembershipKey</ignore>
|
||||||
<ignore>java.net.StandardSocketOptions</ignore>
|
<ignore>java.net.StandardSocketOptions</ignore>
|
||||||
<ignore>java.net.StandardProtocolFamily</ignore>
|
<ignore>java.net.StandardProtocolFamily</ignore>
|
||||||
|
<!-- Used for NIO2 -->
|
||||||
|
<ignore>java.nio.channels.AsynchronousChannel</ignore>
|
||||||
|
<ignore>java.nio.channels.AsynchronousSocketChannel</ignore>
|
||||||
|
<ignore>java.nio.channels.AsynchronousServerSocketChannel</ignore>
|
||||||
|
<ignore>java.nio.channels.AsynchronousChannelGroup</ignore>
|
||||||
</ignores>
|
</ignores>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
@ -85,7 +85,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
private ClosedChannelException closedChannelException;
|
private ClosedChannelException closedChannelException;
|
||||||
private final Deque<FlushCheckpoint> flushCheckpoints = new ArrayDeque<FlushCheckpoint>();
|
private final Deque<FlushCheckpoint> flushCheckpoints = new ArrayDeque<FlushCheckpoint>();
|
||||||
private long writeCounter;
|
private long writeCounter;
|
||||||
private boolean inFlushNow;
|
protected boolean inFlushNow;
|
||||||
private boolean flushNowPending;
|
private boolean flushNowPending;
|
||||||
|
|
||||||
/** Cache for the string representation of this channel */
|
/** Cache for the string representation of this channel */
|
||||||
@ -623,7 +623,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void flushNow() {
|
public void flushNow() {
|
||||||
if (inFlushNow) {
|
if (inFlushNow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -631,12 +631,13 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
inFlushNow = true;
|
inFlushNow = true;
|
||||||
ChannelHandlerContext ctx = directOutboundContext();
|
ChannelHandlerContext ctx = directOutboundContext();
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
|
boolean handleFlush = true;
|
||||||
try {
|
try {
|
||||||
if (ctx.hasOutboundByteBuffer()) {
|
if (ctx.hasOutboundByteBuffer()) {
|
||||||
ByteBuf out = ctx.outboundByteBuffer();
|
ByteBuf out = ctx.outboundByteBuffer();
|
||||||
int oldSize = out.readableBytes();
|
int oldSize = out.readableBytes();
|
||||||
try {
|
try {
|
||||||
doFlushByteBuffer(out);
|
handleFlush = doFlushByteBuffer(out);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
cause = t;
|
cause = t;
|
||||||
} finally {
|
} finally {
|
||||||
@ -657,14 +658,15 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
writeCounter += oldSize - out.size();
|
writeCounter += oldSize - out.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (handleFlush) {
|
||||||
if (cause == null) {
|
if (cause == null) {
|
||||||
notifyFlushFutures();
|
notifyFlushFutures();
|
||||||
} else {
|
} else {
|
||||||
notifyFlushFutures(cause);
|
notifyFlushFutures(cause);
|
||||||
pipeline.fireExceptionCaught(cause);
|
pipeline.fireExceptionCaught(cause);
|
||||||
if (cause instanceof IOException) {
|
if (cause instanceof IOException) {
|
||||||
close(voidFuture());
|
close(voidFuture());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -713,7 +715,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
|
|
||||||
protected abstract void doClose() throws Exception;
|
protected abstract void doClose() throws Exception;
|
||||||
protected abstract void doDeregister() throws Exception;
|
protected abstract void doDeregister() throws Exception;
|
||||||
protected void doFlushByteBuffer(ByteBuf buf) throws Exception {
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
protected void doFlushMessageBuffer(MessageBuf<Object> buf) throws Exception {
|
protected void doFlushMessageBuffer(MessageBuf<Object> buf) throws Exception {
|
||||||
@ -722,7 +724,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
|
|
||||||
protected abstract boolean isFlushPending();
|
protected abstract boolean isFlushPending();
|
||||||
|
|
||||||
private void notifyFlushFutures() {
|
protected final void notifyFlushFutures() {
|
||||||
if (flushCheckpoints.isEmpty()) {
|
if (flushCheckpoints.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -760,7 +762,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyFlushFutures(Throwable cause) {
|
protected final void notifyFlushFutures(Throwable cause) {
|
||||||
notifyFlushFutures();
|
notifyFlushFutures();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
FlushCheckpoint cp = flushCheckpoints.poll();
|
FlushCheckpoint cp = flushCheckpoints.poll();
|
||||||
|
@ -77,7 +77,7 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFlushByteBuffer(ByteBuf buf) throws Exception {
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +71,11 @@ public class EmbeddedByteChannel extends AbstractEmbeddedChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFlushByteBuffer(ByteBuf buf) throws Exception {
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
if (!lastOutboundBuffer().readable()) {
|
if (!lastOutboundBuffer().readable()) {
|
||||||
lastOutboundBuffer().discardReadBytes();
|
lastOutboundBuffer().discardReadBytes();
|
||||||
}
|
}
|
||||||
lastOutboundBuffer().writeBytes(buf);
|
lastOutboundBuffer().writeBytes(buf);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,11 +85,11 @@ abstract class AbstractNioByteChannel extends AbstractNioChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFlushByteBuffer(ByteBuf buf) throws Exception {
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
if (!buf.readable()) {
|
if (!buf.readable()) {
|
||||||
// Reset reader/writerIndex to 0 if the buffer is empty.
|
// Reset reader/writerIndex to 0 if the buffer is empty.
|
||||||
buf.clear();
|
buf.clear();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) {
|
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) {
|
||||||
@ -103,6 +103,7 @@ abstract class AbstractNioByteChannel extends AbstractNioChannel {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int doReadBytes(ByteBuf buf) throws Exception;
|
protected abstract int doReadBytes(ByteBuf buf) throws Exception;
|
||||||
|
176
transport/src/main/java/io/netty/channel/socket/nio2/AbstractAsyncChannel.java
Executable file
176
transport/src/main/java/io/netty/channel/socket/nio2/AbstractAsyncChannel.java
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.socket.nio2;
|
||||||
|
|
||||||
|
import io.netty.channel.AbstractChannel;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelConfig;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.EventLoop;
|
||||||
|
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.channels.AsynchronousChannel;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public abstract class AbstractAsyncChannel extends AbstractChannel {
|
||||||
|
|
||||||
|
protected volatile AsynchronousChannel ch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The future of the current connection attempt. If not null, subsequent
|
||||||
|
* connection attempts will fail.
|
||||||
|
*/
|
||||||
|
protected ChannelFuture connectFuture;
|
||||||
|
protected ScheduledFuture<?> connectTimeoutFuture;
|
||||||
|
private ConnectException connectTimeoutException;
|
||||||
|
|
||||||
|
protected AbstractAsyncChannel(Channel parent, Integer id) {
|
||||||
|
super(parent, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress localAddress() {
|
||||||
|
if (ch == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (InetSocketAddress) super.localAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress remoteAddress() {
|
||||||
|
if (ch == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (InetSocketAddress) super.remoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AsynchronousChannel javaChannel() {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelConfig config() {
|
||||||
|
// TODO: Fix me
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return ch == null || ch.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isCompatible(EventLoop loop) {
|
||||||
|
// TODO: Fix me
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doDeregister() throws Exception {
|
||||||
|
throw new UnsupportedOperationException("Deregistration is not supported by AbstractAsyncChannel");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AsyncUnsafe newUnsafe() {
|
||||||
|
return new AsyncUnsafe();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class AsyncUnsafe extends AbstractUnsafe {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(final SocketAddress remoteAddress,
|
||||||
|
final SocketAddress localAddress, final ChannelFuture future) {
|
||||||
|
if (eventLoop().inEventLoop()) {
|
||||||
|
if (!ensureOpen(future)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (connectFuture != null) {
|
||||||
|
throw new IllegalStateException("connection attempt already made");
|
||||||
|
}
|
||||||
|
connectFuture = future;
|
||||||
|
|
||||||
|
doConnect(remoteAddress, localAddress, future);
|
||||||
|
|
||||||
|
// Schedule connect timeout.
|
||||||
|
int connectTimeoutMillis = config().getConnectTimeoutMillis();
|
||||||
|
if (connectTimeoutMillis > 0) {
|
||||||
|
connectTimeoutFuture = eventLoop().schedule(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (connectTimeoutException == null) {
|
||||||
|
connectTimeoutException = new ConnectException("connection timed out");
|
||||||
|
}
|
||||||
|
ChannelFuture connectFuture = AbstractAsyncChannel.this.connectFuture;
|
||||||
|
if (connectFuture != null &&
|
||||||
|
connectFuture.setFailure(connectTimeoutException)) {
|
||||||
|
pipeline().fireExceptionCaught(connectTimeoutException);
|
||||||
|
close(voidFuture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, connectTimeoutMillis, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable t) {
|
||||||
|
future.setFailure(t);
|
||||||
|
pipeline().fireExceptionCaught(t);
|
||||||
|
closeIfClosed();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventLoop().execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
connect(remoteAddress, localAddress, future);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void connectFailed(Throwable t) {
|
||||||
|
connectFuture.setFailure(t);
|
||||||
|
pipeline().fireExceptionCaught(t);
|
||||||
|
closeIfClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void connectSuccess() {
|
||||||
|
assert eventLoop().inEventLoop();
|
||||||
|
assert connectFuture != null;
|
||||||
|
try {
|
||||||
|
boolean wasActive = isActive();
|
||||||
|
connectFuture.setSuccess();
|
||||||
|
if (!wasActive && isActive()) {
|
||||||
|
pipeline().fireChannelActive();
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
connectFuture.setFailure(t);
|
||||||
|
pipeline().fireExceptionCaught(t);
|
||||||
|
closeIfClosed();
|
||||||
|
} finally {
|
||||||
|
connectTimeoutFuture.cancel(false);
|
||||||
|
connectFuture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected abstract void doConnect(SocketAddress remoteAddress,
|
||||||
|
SocketAddress localAddress, ChannelFuture connectFuture);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.socket.nio2;
|
||||||
|
|
||||||
|
import io.netty.buffer.ChannelBufType;
|
||||||
|
import io.netty.channel.ChannelException;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ServerChannel;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.channels.AsynchronousChannelGroup;
|
||||||
|
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.nio.channels.CompletionHandler;
|
||||||
|
|
||||||
|
public class AsyncServerSocketChannel extends AbstractAsyncChannel implements ServerChannel {
|
||||||
|
|
||||||
|
private static final AcceptHandler ACCEPT_HANDLER = new AcceptHandler();
|
||||||
|
private static final InternalLogger logger =
|
||||||
|
InternalLoggerFactory.getInstance(AsyncServerSocketChannel.class);
|
||||||
|
|
||||||
|
public AsyncServerSocketChannel() {
|
||||||
|
super(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AsynchronousServerSocketChannel javaChannel() {
|
||||||
|
return (AsynchronousServerSocketChannel) super.javaChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return localAddress0() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelBufType bufferType() {
|
||||||
|
return ChannelBufType.MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SocketAddress localAddress0() {
|
||||||
|
try {
|
||||||
|
return javaChannel().getLocalAddress();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ChannelException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SocketAddress remoteAddress0() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
|
javaChannel().bind(localAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doClose() throws Exception {
|
||||||
|
javaChannel().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isFlushPending() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doConnect(
|
||||||
|
SocketAddress remoteAddress, SocketAddress localAddress, ChannelFuture future) {
|
||||||
|
future.setFailure(new UnsupportedOperationException());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doDisconnect() throws Exception {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Runnable doRegister() throws Exception {
|
||||||
|
ch = AsynchronousServerSocketChannel.open(AsynchronousChannelGroup.withThreadPool(eventLoop()));
|
||||||
|
javaChannel().accept(this, ACCEPT_HANDLER);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AcceptHandler
|
||||||
|
implements CompletionHandler<AsynchronousSocketChannel, AsyncServerSocketChannel> {
|
||||||
|
public void completed(AsynchronousSocketChannel ch, AsyncServerSocketChannel channel) {
|
||||||
|
// register again this handler to accept new connections
|
||||||
|
channel.javaChannel().accept(channel, this);
|
||||||
|
|
||||||
|
// create the socket add it to the buffer and fire the event
|
||||||
|
channel.outboundMessageBuffer().add(new AsyncSocketchannel(channel, null));
|
||||||
|
channel.pipeline().fireInboundBufferUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void failed(Throwable t, AsyncServerSocketChannel channel) {
|
||||||
|
logger.warn("Failed to create a new channel from an accepted socket.", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
246
transport/src/main/java/io/netty/channel/socket/nio2/AsyncSocketchannel.java
Executable file
246
transport/src/main/java/io/netty/channel/socket/nio2/AsyncSocketchannel.java
Executable file
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.socket.nio2;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ChannelBufType;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.channels.AsynchronousChannelGroup;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.nio.channels.CompletionHandler;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class AsyncSocketchannel extends AbstractAsyncChannel {
|
||||||
|
|
||||||
|
private static final CompletionHandler<Void, AsyncSocketchannel> CONNECT_HANDLER = new ConnectHandler();
|
||||||
|
private static final CompletionHandler<Integer, AsyncSocketchannel> READ_HANDLER = new ReadHandler();
|
||||||
|
private static final CompletionHandler<Integer, AsyncSocketchannel> WRITE_HANDLER = new WriteHandler();
|
||||||
|
|
||||||
|
private final AtomicBoolean flushing = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public AsyncSocketchannel() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncSocketchannel(AsyncServerSocketChannel parent, Integer id) {
|
||||||
|
super(parent, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
AsynchronousSocketChannel ch = javaChannel();
|
||||||
|
return ch.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AsynchronousSocketChannel javaChannel() {
|
||||||
|
return (AsynchronousSocketChannel) super.javaChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelBufType bufferType() {
|
||||||
|
return ChannelBufType.BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress, final ChannelFuture future) {
|
||||||
|
assert ch != null;
|
||||||
|
if (localAddress != null) {
|
||||||
|
try {
|
||||||
|
javaChannel().bind(localAddress);
|
||||||
|
} catch (IOException e) {
|
||||||
|
future.setFailure(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
javaChannel().connect(remoteAddress, this, CONNECT_HANDLER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InetSocketAddress localAddress0() {
|
||||||
|
try {
|
||||||
|
return (InetSocketAddress) javaChannel().getLocalAddress();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InetSocketAddress remoteAddress0() {
|
||||||
|
try {
|
||||||
|
return (InetSocketAddress) javaChannel().getRemoteAddress();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Runnable doRegister() throws Exception {
|
||||||
|
assert ch == null;
|
||||||
|
ch = AsynchronousSocketChannel.open(AsynchronousChannelGroup.withThreadPool(eventLoop()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void read() {
|
||||||
|
javaChannel().read(pipeline().inboundByteBuffer().nioBuffer(), this, READ_HANDLER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
|
javaChannel().bind(localAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doDisconnect() throws Exception {
|
||||||
|
doClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doClose() throws Exception {
|
||||||
|
javaChannel().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isFlushPending() {
|
||||||
|
// TODO: Fix me
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
|
if (flushing.compareAndSet(false, true)) {
|
||||||
|
javaChannel().write(buf.nioBuffer(), this, WRITE_HANDLER);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean expandReadBuffer(ByteBuf byteBuf) {
|
||||||
|
if (!byteBuf.writable()) {
|
||||||
|
// FIXME: Magic number
|
||||||
|
byteBuf.ensureWritableBytes(4096);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class WriteHandler implements CompletionHandler<Integer, AsyncSocketchannel> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completed(Integer result, AsyncSocketchannel channel) {
|
||||||
|
ByteBuf buf = channel.pipeline().outboundByteBuffer();
|
||||||
|
if (!buf.readable()) {
|
||||||
|
buf.discardReadBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
channel.notifyFlushFutures();
|
||||||
|
}
|
||||||
|
channel.flushing.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable cause, AsyncSocketchannel channel) {
|
||||||
|
ByteBuf buf = channel.pipeline().outboundByteBuffer();
|
||||||
|
if (!buf.readable()) {
|
||||||
|
buf.discardReadBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.notifyFlushFutures(cause);
|
||||||
|
channel.pipeline().fireExceptionCaught(cause);
|
||||||
|
if (cause instanceof IOException) {
|
||||||
|
channel.close(channel.unsafe().voidFuture());
|
||||||
|
}
|
||||||
|
channel.flushing.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReadHandler implements CompletionHandler<Integer, AsyncSocketchannel> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completed(Integer result, AsyncSocketchannel channel) {
|
||||||
|
assert channel.eventLoop().inEventLoop();
|
||||||
|
|
||||||
|
final ChannelPipeline pipeline = channel.pipeline();
|
||||||
|
final ByteBuf byteBuf = pipeline.inboundByteBuffer();
|
||||||
|
boolean closed = false;
|
||||||
|
boolean read = false;
|
||||||
|
try {
|
||||||
|
expandReadBuffer(byteBuf);
|
||||||
|
for (;;) {
|
||||||
|
int localReadAmount = result.intValue();
|
||||||
|
if (localReadAmount > 0) {
|
||||||
|
read = true;
|
||||||
|
} else if (localReadAmount < 0) {
|
||||||
|
closed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!expandReadBuffer(byteBuf)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (read) {
|
||||||
|
read = false;
|
||||||
|
pipeline.fireInboundBufferUpdated();
|
||||||
|
}
|
||||||
|
pipeline.fireExceptionCaught(t);
|
||||||
|
if (t instanceof IOException) {
|
||||||
|
channel.close(channel.unsafe().voidFuture());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (read) {
|
||||||
|
pipeline.fireInboundBufferUpdated();
|
||||||
|
}
|
||||||
|
if (closed && channel.isOpen()) {
|
||||||
|
channel.close(channel.unsafe().voidFuture());
|
||||||
|
} else {
|
||||||
|
// start the next read
|
||||||
|
channel.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable t, AsyncSocketchannel channel) {
|
||||||
|
channel.pipeline().fireExceptionCaught(t);
|
||||||
|
if (t instanceof IOException) {
|
||||||
|
channel.close(channel.unsafe().voidFuture());
|
||||||
|
} else {
|
||||||
|
// start the next read
|
||||||
|
channel.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ConnectHandler implements CompletionHandler<Void, AsyncSocketchannel> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void completed(Void result, AsyncSocketchannel channel) {
|
||||||
|
((AsyncUnsafe) channel.unsafe()).connectSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable exc, AsyncSocketchannel channel) {
|
||||||
|
((AsyncUnsafe) channel.unsafe()).connectFailed(exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://en.wikipedia.org/wiki/New_I/O">NIO2</a>-based socket channel
|
||||||
|
* API implementation - recommended for a large number of connections (>= 1000).
|
||||||
|
*/
|
||||||
|
package io.netty.channel.socket.nio2;
|
@ -86,11 +86,12 @@ abstract class AbstractOioByteChannel extends AbstractOioChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFlushByteBuffer(ByteBuf buf) throws Exception {
|
protected boolean doFlushByteBuffer(ByteBuf buf) throws Exception {
|
||||||
while (buf.readable()) {
|
while (buf.readable()) {
|
||||||
doWriteBytes(buf);
|
doWriteBytes(buf);
|
||||||
}
|
}
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int available();
|
protected abstract int available();
|
||||||
|
Loading…
Reference in New Issue
Block a user