* Merged recent changes in the trunk to the NIO UDP transport
* Other miscellaneous modifications like typo fix
This commit is contained in:
parent
e4871f8460
commit
899b16678f
@ -25,7 +25,9 @@ package org.jboss.netty.channel.socket.nio;
|
|||||||
import static org.jboss.netty.channel.Channels.*;
|
import static org.jboss.netty.channel.Channels.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
@ -34,16 +36,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
import org.jboss.netty.buffer.ChannelBuffer;
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
import org.jboss.netty.channel.AbstractChannel;
|
import org.jboss.netty.channel.AbstractChannel;
|
||||||
|
import org.jboss.netty.channel.Channel;
|
||||||
import org.jboss.netty.channel.ChannelException;
|
import org.jboss.netty.channel.ChannelException;
|
||||||
import org.jboss.netty.channel.ChannelFactory;
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
import org.jboss.netty.channel.ChannelPipeline;
|
import org.jboss.netty.channel.ChannelPipeline;
|
||||||
import org.jboss.netty.channel.ChannelSink;
|
import org.jboss.netty.channel.ChannelSink;
|
||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
import org.jboss.netty.channel.ServerChannel;
|
|
||||||
import org.jboss.netty.channel.socket.DatagramChannelConfig;
|
import org.jboss.netty.channel.socket.DatagramChannelConfig;
|
||||||
import org.jboss.netty.logging.InternalLogger;
|
|
||||||
import org.jboss.netty.logging.InternalLoggerFactory;
|
|
||||||
import org.jboss.netty.util.internal.LinkedTransferQueue;
|
import org.jboss.netty.util.internal.LinkedTransferQueue;
|
||||||
import org.jboss.netty.util.internal.ThreadLocalBoolean;
|
import org.jboss.netty.util.internal.ThreadLocalBoolean;
|
||||||
|
|
||||||
@ -56,13 +56,8 @@ import org.jboss.netty.util.internal.ThreadLocalBoolean;
|
|||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*/
|
*/
|
||||||
public class NioDatagramChannel extends AbstractChannel implements
|
class NioDatagramChannel extends AbstractChannel
|
||||||
ServerChannel {
|
implements org.jboss.netty.channel.socket.DatagramChannel {
|
||||||
/**
|
|
||||||
* Internal Netty logger.
|
|
||||||
*/
|
|
||||||
private static final InternalLogger logger = InternalLoggerFactory
|
|
||||||
.getInstance(NioDatagramChannel.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link DatagramChannelConfig}.
|
* The {@link DatagramChannelConfig}.
|
||||||
@ -77,7 +72,7 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
/**
|
/**
|
||||||
* The {@link DatagramChannel} that this channel uses.
|
* The {@link DatagramChannel} that this channel uses.
|
||||||
*/
|
*/
|
||||||
private final DatagramChannel datagramChannel;
|
private final java.nio.channels.DatagramChannel datagramChannel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monitor object to synchronize access to InterestedOps.
|
* Monitor object to synchronize access to InterestedOps.
|
||||||
@ -120,30 +115,17 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
*/
|
*/
|
||||||
MessageEvent currentWriteEvent;
|
MessageEvent currentWriteEvent;
|
||||||
|
|
||||||
/**
|
|
||||||
* The current write index.
|
|
||||||
*/
|
|
||||||
int currentWriteIndex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean that indicates that write operation is in progress.
|
* Boolean that indicates that write operation is in progress.
|
||||||
*/
|
*/
|
||||||
volatile boolean inWriteNowLoop;
|
volatile boolean inWriteNowLoop;
|
||||||
|
|
||||||
/**
|
NioDatagramChannel(final ChannelFactory factory,
|
||||||
*
|
|
||||||
* @param factory
|
|
||||||
* @param pipeline
|
|
||||||
* @param sink
|
|
||||||
* @param worker
|
|
||||||
*/
|
|
||||||
public NioDatagramChannel(final ChannelFactory factory,
|
|
||||||
final ChannelPipeline pipeline, final ChannelSink sink,
|
final ChannelPipeline pipeline, final ChannelSink sink,
|
||||||
final NioUdpWorker worker) {
|
final NioUdpWorker worker) {
|
||||||
super(null, factory, pipeline, sink);
|
super(null, factory, pipeline, sink);
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
datagramChannel = openNonBlockingChannel();
|
datagramChannel = openNonBlockingChannel();
|
||||||
setSoTimeout(1000);
|
|
||||||
config = new DefaultNioDatagramChannelConfig(datagramChannel.socket());
|
config = new DefaultNioDatagramChannelConfig(datagramChannel.socket());
|
||||||
|
|
||||||
fireChannelOpen(this);
|
fireChannelOpen(this);
|
||||||
@ -159,27 +141,22 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSoTimeout(final int timeout) {
|
public InetSocketAddress getLocalAddress() {
|
||||||
try {
|
try {
|
||||||
datagramChannel.socket().setSoTimeout(timeout);
|
return (InetSocketAddress) datagramChannel.socket().getLocalSocketAddress();
|
||||||
} catch (final IOException e) {
|
} catch (Throwable t) {
|
||||||
try {
|
// Sometimes fails on a closed socket in Windows.
|
||||||
datagramChannel.close();
|
return null;
|
||||||
} catch (final IOException e2) {
|
|
||||||
logger.warn("Failed to close a partially DatagramSocket.", e2);
|
|
||||||
}
|
|
||||||
throw new ChannelException(
|
|
||||||
"Failed to set the DatagramSocket timeout.", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public InetSocketAddress getLocalAddress() {
|
public InetSocketAddress getRemoteAddress() {
|
||||||
return (InetSocketAddress) datagramChannel.socket()
|
try {
|
||||||
.getLocalSocketAddress();
|
return (InetSocketAddress) datagramChannel.socket().getRemoteSocketAddress();
|
||||||
}
|
} catch (Throwable t) {
|
||||||
|
// Sometimes fails on a closed socket in Windows.
|
||||||
public SocketAddress getRemoteAddress() {
|
return null;
|
||||||
return datagramChannel.socket().getRemoteSocketAddress();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBound() {
|
public boolean isBound() {
|
||||||
@ -187,7 +164,7 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return datagramChannel.socket().isBound();
|
return datagramChannel.socket().isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -195,11 +172,6 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
return super.setClosed();
|
return super.setClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ChannelFuture getSucceededFuture() {
|
|
||||||
return super.getSucceededFuture();
|
|
||||||
}
|
|
||||||
|
|
||||||
public NioDatagramChannelConfig getConfig() {
|
public NioDatagramChannelConfig getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@ -208,6 +180,37 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
return datagramChannel;
|
return datagramChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInterestOps() {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return Channel.OP_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int interestOps = getRawInterestOps();
|
||||||
|
int writeBufferSize = this.writeBufferSize.get();
|
||||||
|
if (writeBufferSize != 0) {
|
||||||
|
if (highWaterMarkCounter.get() > 0) {
|
||||||
|
int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
|
||||||
|
if (writeBufferSize >= lowWaterMark) {
|
||||||
|
interestOps |= Channel.OP_WRITE;
|
||||||
|
} else {
|
||||||
|
interestOps &= ~Channel.OP_WRITE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int highWaterMark = getConfig().getWriteBufferHighWaterMark();
|
||||||
|
if (writeBufferSize >= highWaterMark) {
|
||||||
|
interestOps |= Channel.OP_WRITE;
|
||||||
|
} else {
|
||||||
|
interestOps &= ~Channel.OP_WRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
interestOps &= ~Channel.OP_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return interestOps;
|
||||||
|
}
|
||||||
|
|
||||||
int getRawInterestOps() {
|
int getRawInterestOps() {
|
||||||
return super.getInterestOps();
|
return super.getInterestOps();
|
||||||
}
|
}
|
||||||
@ -216,6 +219,15 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
super.setInterestOpsNow(interestOps);
|
super.setInterestOpsNow(interestOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture write(Object message, SocketAddress remoteAddress) {
|
||||||
|
if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) {
|
||||||
|
return super.write(message, null);
|
||||||
|
} else {
|
||||||
|
return super.write(message, remoteAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WriteBuffer is an extension of {@link LinkedTransferQueue} that adds
|
* WriteBuffer is an extension of {@link LinkedTransferQueue} that adds
|
||||||
* support for highWaterMark checking of the write buffer size.
|
* support for highWaterMark checking of the write buffer size.
|
||||||
@ -233,21 +245,17 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
* adds support for keeping track of the size of the this write buffer.
|
* adds support for keeping track of the size of the this write buffer.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean offer(final MessageEvent e) {
|
public boolean offer(MessageEvent e) {
|
||||||
final boolean success = super.offer(e);
|
boolean success = super.offer(e);
|
||||||
assert success;
|
assert success;
|
||||||
|
|
||||||
final int messageSize = ((ChannelBuffer) e.getMessage())
|
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes();
|
||||||
.readableBytes();
|
int newWriteBufferSize = writeBufferSize.addAndGet(messageSize);
|
||||||
|
int highWaterMark = getConfig().getWriteBufferHighWaterMark();
|
||||||
|
|
||||||
final int newWriteBufferSize = writeBufferSize
|
|
||||||
.addAndGet(messageSize);
|
|
||||||
|
|
||||||
final int highWaterMark = getConfig().getWriteBufferHighWaterMark();
|
|
||||||
if (newWriteBufferSize >= highWaterMark) {
|
if (newWriteBufferSize >= highWaterMark) {
|
||||||
if (newWriteBufferSize - messageSize < highWaterMark) {
|
if (newWriteBufferSize - messageSize < highWaterMark) {
|
||||||
highWaterMarkCounter.incrementAndGet();
|
highWaterMarkCounter.incrementAndGet();
|
||||||
|
|
||||||
if (!notifying.get()) {
|
if (!notifying.get()) {
|
||||||
notifying.set(Boolean.TRUE);
|
notifying.set(Boolean.TRUE);
|
||||||
fireChannelInterestChanged(NioDatagramChannel.this);
|
fireChannelInterestChanged(NioDatagramChannel.this);
|
||||||
@ -255,7 +263,6 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,18 +272,13 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MessageEvent poll() {
|
public MessageEvent poll() {
|
||||||
final MessageEvent e = super.poll();
|
MessageEvent e = super.poll();
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
final int messageSize = ((ChannelBuffer) e.getMessage())
|
int messageSize = ((ChannelBuffer) e.getMessage()).readableBytes();
|
||||||
.readableBytes();
|
int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize);
|
||||||
final int newWriteBufferSize = writeBufferSize
|
int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
|
||||||
.addAndGet(-messageSize);
|
|
||||||
|
|
||||||
final int lowWaterMark = getConfig()
|
if (newWriteBufferSize == 0 || newWriteBufferSize < lowWaterMark) {
|
||||||
.getWriteBufferLowWaterMark();
|
|
||||||
|
|
||||||
if (newWriteBufferSize == 0 ||
|
|
||||||
newWriteBufferSize < lowWaterMark) {
|
|
||||||
if (newWriteBufferSize + messageSize >= lowWaterMark) {
|
if (newWriteBufferSize + messageSize >= lowWaterMark) {
|
||||||
highWaterMarkCounter.decrementAndGet();
|
highWaterMarkCounter.decrementAndGet();
|
||||||
if (!notifying.get()) {
|
if (!notifying.get()) {
|
||||||
@ -305,4 +307,22 @@ public class NioDatagramChannel extends AbstractChannel implements
|
|||||||
NioUdpWorker.write(NioDatagramChannel.this, false);
|
NioUdpWorker.write(NioDatagramChannel.this, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void joinGroup(InetAddress multicastAddress) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void joinGroup(InetSocketAddress multicastAddress,
|
||||||
|
NetworkInterface networkInterface) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void leaveGroup(InetAddress multicastAddress) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void leaveGroup(InetSocketAddress multicastAddress,
|
||||||
|
NetworkInterface networkInterface) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,14 +25,14 @@ package org.jboss.netty.channel.socket.nio;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import org.jboss.netty.channel.Channel;
|
import org.jboss.netty.channel.Channel;
|
||||||
import org.jboss.netty.channel.ChannelFactory;
|
|
||||||
import org.jboss.netty.channel.ChannelPipeline;
|
import org.jboss.netty.channel.ChannelPipeline;
|
||||||
import org.jboss.netty.channel.ServerChannelFactory;
|
import org.jboss.netty.channel.socket.DatagramChannel;
|
||||||
|
import org.jboss.netty.channel.socket.DatagramChannelFactory;
|
||||||
import org.jboss.netty.util.internal.ExecutorUtil;
|
import org.jboss.netty.util.internal.ExecutorUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link NioDatagramChannelFactory} creates a server-side NIO-based
|
* A {@link NioDatagramChannelFactory} creates a server-side NIO-based
|
||||||
* {@link NioDatagramChannel}. It utilizes the non-blocking I/O mode which
|
* {@link DatagramChannel}. It utilizes the non-blocking I/O mode which
|
||||||
* was introduced with NIO to serve many number of concurrent connections
|
* was introduced with NIO to serve many number of concurrent connections
|
||||||
* efficiently.
|
* efficiently.
|
||||||
*
|
*
|
||||||
@ -59,8 +59,7 @@ import org.jboss.netty.util.internal.ExecutorUtil;
|
|||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*/
|
*/
|
||||||
public class NioDatagramChannelFactory implements ChannelFactory,
|
public class NioDatagramChannelFactory implements DatagramChannelFactory {
|
||||||
ServerChannelFactory {
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -102,7 +101,7 @@ public class NioDatagramChannelFactory implements ChannelFactory,
|
|||||||
sink = new NioDatagramPipelineSink(workerExecutor, workerCount);
|
sink = new NioDatagramPipelineSink(workerExecutor, workerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NioDatagramChannel newChannel(final ChannelPipeline pipeline) {
|
public DatagramChannel newChannel(final ChannelPipeline pipeline) {
|
||||||
return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker());
|
return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ import org.jboss.netty.channel.MessageEvent;
|
|||||||
*
|
*
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
*/
|
*/
|
||||||
public class NioDatagramPipelineSink extends AbstractChannelSink {
|
class NioDatagramPipelineSink extends AbstractChannelSink {
|
||||||
|
|
||||||
private static final AtomicInteger nextId = new AtomicInteger();
|
private static final AtomicInteger nextId = new AtomicInteger();
|
||||||
|
|
||||||
@ -74,8 +74,9 @@ public class NioDatagramPipelineSink extends AbstractChannelSink {
|
|||||||
/**
|
/**
|
||||||
* Handle downstream event.
|
* Handle downstream event.
|
||||||
*
|
*
|
||||||
* @param pipeline The channelpiple line that passed down the downstream event.
|
* @param pipeline the {@link ChannelPipeline} that passes down the
|
||||||
* @param event The downstream event.
|
* downstream event.
|
||||||
|
* @param e The downstream event.
|
||||||
*/
|
*/
|
||||||
public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e)
|
public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -98,6 +99,14 @@ public class NioDatagramPipelineSink extends AbstractChannelSink {
|
|||||||
NioUdpWorker.close(channel, future);
|
NioUdpWorker.close(channel, future);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CONNECTED:
|
||||||
|
// TODO Implement me
|
||||||
|
if (value != null) {
|
||||||
|
//connect(channel, future, (SocketAddress) value);
|
||||||
|
} else {
|
||||||
|
//NioUdpWorker.disconnect(channel, future);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case INTEREST_OPS:
|
case INTEREST_OPS:
|
||||||
NioUdpWorker.setInterestOps(channel, future, ((Integer) value)
|
NioUdpWorker.setInterestOps(channel, future, ((Integer) value)
|
||||||
.intValue());
|
.intValue());
|
||||||
|
@ -49,6 +49,7 @@ import org.jboss.netty.channel.Channel;
|
|||||||
import org.jboss.netty.channel.ChannelException;
|
import org.jboss.netty.channel.ChannelException;
|
||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
import org.jboss.netty.channel.MessageEvent;
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
|
import org.jboss.netty.channel.ReceiveBufferSizePredictor;
|
||||||
import org.jboss.netty.logging.InternalLogger;
|
import org.jboss.netty.logging.InternalLogger;
|
||||||
import org.jboss.netty.logging.InternalLoggerFactory;
|
import org.jboss.netty.logging.InternalLoggerFactory;
|
||||||
import org.jboss.netty.util.ThreadRenamingRunnable;
|
import org.jboss.netty.util.ThreadRenamingRunnable;
|
||||||
@ -71,12 +72,6 @@ class NioUdpWorker implements Runnable {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory
|
private static final InternalLogger logger = InternalLoggerFactory
|
||||||
.getInstance(NioUdpWorker.class);
|
.getInstance(NioUdpWorker.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum packate size for UDP packets.
|
|
||||||
* 65,536-byte maximum size of an IP datagram minus the 20-byte size of the IP header and the 8-byte size of the UDP header.
|
|
||||||
*/
|
|
||||||
private static int MAX_PACKET_SIZE = 65507;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This id of this worker.
|
* This id of this worker.
|
||||||
*/
|
*/
|
||||||
@ -321,17 +316,21 @@ class NioUdpWorker implements Runnable {
|
|||||||
|
|
||||||
private static void processSelectedKeys(final Set<SelectionKey> selectedKeys) {
|
private static void processSelectedKeys(final Set<SelectionKey> selectedKeys) {
|
||||||
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
|
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
|
||||||
final SelectionKey key = i.next();
|
SelectionKey k = i.next();
|
||||||
i.remove();
|
i.remove();
|
||||||
try {
|
try {
|
||||||
if (key.isReadable()) {
|
int readyOps = k.readyOps();
|
||||||
read(key);
|
if ((readyOps & SelectionKey.OP_READ) != 0) {
|
||||||
|
if (!read(k)) {
|
||||||
|
// Connection already closed - no need to handle write.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (key.isWritable()) {
|
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
|
||||||
write(key);
|
write(k);
|
||||||
}
|
}
|
||||||
} catch (final CancelledKeyException ignore) {
|
} catch (CancelledKeyException e) {
|
||||||
close(key);
|
close(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,40 +346,57 @@ class NioUdpWorker implements Runnable {
|
|||||||
*
|
*
|
||||||
* @param key The selection key which contains the Selector registration information.
|
* @param key The selection key which contains the Selector registration information.
|
||||||
*/
|
*/
|
||||||
private static void read(final SelectionKey key) {
|
private static boolean read(final SelectionKey key) {
|
||||||
final NioDatagramChannel nioDatagramChannel = (NioDatagramChannel) key
|
final NioDatagramChannel channel = (NioDatagramChannel) key.attachment();
|
||||||
.attachment();
|
ReceiveBufferSizePredictor predictor =
|
||||||
|
channel.getConfig().getReceiveBufferSizePredictor();
|
||||||
|
|
||||||
final DatagramChannel datagramChannel = (DatagramChannel) key.channel();
|
final DatagramChannel nioChannel = (DatagramChannel) key.channel();
|
||||||
|
|
||||||
|
// Allocating a non-direct buffer with a max udp packge size.
|
||||||
|
// Would using a direct buffer be more efficient or would this negatively
|
||||||
|
// effect performance, as direct buffer allocation has a higher upfront cost
|
||||||
|
// where as a ByteBuffer is heap allocated.
|
||||||
|
final ByteBuffer byteBuffer = ByteBuffer.allocate(predictor.nextReceiveBufferSize());
|
||||||
|
|
||||||
|
boolean failure = true;
|
||||||
|
SocketAddress remoteAddress = null;
|
||||||
try {
|
try {
|
||||||
// Allocating a non-direct buffer with a max udp packge size.
|
// Receive from the channel in a non blocking mode. We have already been notified that
|
||||||
// Would using a direct buffer be more efficient or would this negatively
|
|
||||||
// effect performance, as direct buffer allocation has a higher upfront cost
|
|
||||||
// where as a ByteBuffer is heap allocated.
|
|
||||||
final ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
|
|
||||||
|
|
||||||
// Recieve from the channel in a non blocking mode. We have already been notified that
|
|
||||||
// the channel is ready to receive.
|
// the channel is ready to receive.
|
||||||
final SocketAddress remoteAddress = datagramChannel
|
remoteAddress = nioChannel.receive(byteBuffer);
|
||||||
.receive(byteBuffer);
|
failure = false;
|
||||||
|
} catch (AsynchronousCloseException e) {
|
||||||
|
// Can happen, and does not need a user attention.
|
||||||
|
} catch (Throwable t) {
|
||||||
|
fireExceptionCaught(channel, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remoteAddress != null) {
|
||||||
// Flip the buffer so that we can wrap it.
|
// Flip the buffer so that we can wrap it.
|
||||||
byteBuffer.flip();
|
byteBuffer.flip();
|
||||||
// Create a Netty ChannelByffer by wrapping the ByteBuffer.
|
|
||||||
final ChannelBuffer channelBuffer = ChannelBuffers
|
|
||||||
.wrappedBuffer(byteBuffer);
|
|
||||||
|
|
||||||
logger.debug("ChannelBuffer : " + channelBuffer +
|
int readBytes = byteBuffer.remaining();
|
||||||
", remoteAdress: " + remoteAddress);
|
if (readBytes > 0) {
|
||||||
|
// Update the predictor.
|
||||||
|
predictor.previousReceiveBufferSize(readBytes);
|
||||||
|
|
||||||
// Notify the interested parties about the newly arrived message (channelBuffer).
|
// Create a Netty ChannelByffer by wrapping the ByteBuffer.
|
||||||
fireMessageReceived(nioDatagramChannel, channelBuffer,
|
final ChannelBuffer channelBuffer = ChannelBuffers
|
||||||
remoteAddress);
|
.wrappedBuffer(byteBuffer);
|
||||||
} catch (final Throwable t) {
|
|
||||||
if (!nioDatagramChannel.getDatagramChannel().socket().isClosed()) {
|
// Notify the interested parties about the newly arrived message (channelBuffer).
|
||||||
fireExceptionCaught(nioDatagramChannel, t);
|
fireMessageReceived(channel, channelBuffer,
|
||||||
|
remoteAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (failure) {
|
||||||
|
close(key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void close(SelectionKey k) {
|
private static void close(SelectionKey k) {
|
||||||
@ -393,7 +409,7 @@ class NioUdpWorker implements Runnable {
|
|||||||
/*
|
/*
|
||||||
* Note that we are not checking if the channel is connected. Connected has a different
|
* Note that we are not checking if the channel is connected. Connected has a different
|
||||||
* meaning in UDP and means that the channels socket is configured to only send and
|
* meaning in UDP and means that the channels socket is configured to only send and
|
||||||
* recieve from a given remote peer.
|
* receive from a given remote peer.
|
||||||
*/
|
*/
|
||||||
if (!channel.isOpen()) {
|
if (!channel.isOpen()) {
|
||||||
cleanUpWriteBuffer(channel);
|
cleanUpWriteBuffer(channel);
|
||||||
@ -444,7 +460,6 @@ class NioUdpWorker implements Runnable {
|
|||||||
|
|
||||||
MessageEvent evt;
|
MessageEvent evt;
|
||||||
ChannelBuffer buf;
|
ChannelBuffer buf;
|
||||||
int bufIdx;
|
|
||||||
int writtenBytes = 0;
|
int writtenBytes = 0;
|
||||||
|
|
||||||
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
|
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
|
||||||
@ -465,33 +480,30 @@ class NioUdpWorker implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf = (ChannelBuffer) evt.getMessage();
|
buf = (ChannelBuffer) evt.getMessage();
|
||||||
bufIdx = buf.readerIndex();
|
|
||||||
} else {
|
} else {
|
||||||
buf = (ChannelBuffer) evt.getMessage();
|
buf = (ChannelBuffer) evt.getMessage();
|
||||||
bufIdx = channel.currentWriteIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
int localWrittenBytes = 0;
|
||||||
for (int i = writeSpinCount; i > 0; i --) {
|
for (int i = writeSpinCount; i > 0; i --) {
|
||||||
ChannelBuffer buffer = (ChannelBuffer) evt.getMessage();
|
localWrittenBytes =
|
||||||
int localWrittenBytes = channel.getDatagramChannel()
|
channel.getDatagramChannel().send(
|
||||||
.send(buffer.toByteBuffer(),
|
buf.toByteBuffer(),
|
||||||
evt.getRemoteAddress());
|
evt.getRemoteAddress());
|
||||||
if (localWrittenBytes != 0) {
|
if (localWrittenBytes != 0) {
|
||||||
bufIdx += localWrittenBytes;
|
|
||||||
writtenBytes += localWrittenBytes;
|
writtenBytes += localWrittenBytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufIdx == buf.writerIndex()) {
|
if (localWrittenBytes > 0) {
|
||||||
// Successful write - proceed to the next message.
|
// Successful write - proceed to the next message.
|
||||||
evt.getFuture().setSuccess();
|
evt.getFuture().setSuccess();
|
||||||
evt = null;
|
evt = null;
|
||||||
} else {
|
} else {
|
||||||
// Not written fully - perhaps the kernel buffer is full.
|
// Not written at all - perhaps the kernel buffer is full.
|
||||||
channel.currentWriteEvent = evt;
|
channel.currentWriteEvent = evt;
|
||||||
channel.currentWriteIndex = bufIdx;
|
|
||||||
addOpWrite = true;
|
addOpWrite = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -590,7 +602,7 @@ class NioUdpWorker implements Runnable {
|
|||||||
key.cancel();
|
key.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean connected = channel.isOpen();
|
boolean connected = channel.isConnected();
|
||||||
boolean bound = channel.isBound();
|
boolean bound = channel.isBound();
|
||||||
try {
|
try {
|
||||||
channel.getDatagramChannel().close();
|
channel.getDatagramChannel().close();
|
||||||
@ -615,33 +627,46 @@ class NioUdpWorker implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void cleanUpWriteBuffer(final NioDatagramChannel channel) {
|
private static void cleanUpWriteBuffer(final NioDatagramChannel channel) {
|
||||||
// Create the exception only once to avoid the excessive overhead
|
Exception cause = null;
|
||||||
// caused by fillStackTrace.
|
|
||||||
Exception cause;
|
|
||||||
if (channel.isOpen()) {
|
|
||||||
cause = new NotYetConnectedException();
|
|
||||||
} else {
|
|
||||||
cause = new ClosedChannelException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the stale messages in the write buffer.
|
// Clean up the stale messages in the write buffer.
|
||||||
synchronized (channel.writeLock) {
|
synchronized (channel.writeLock) {
|
||||||
MessageEvent evt = channel.currentWriteEvent;
|
MessageEvent evt = channel.currentWriteEvent;
|
||||||
if (evt != null) {
|
if (evt != null) {
|
||||||
channel.currentWriteEvent = null;
|
channel.currentWriteEvent = null;
|
||||||
channel.currentWriteIndex = 0;
|
|
||||||
|
// Create the exception only once to avoid the excessive overhead
|
||||||
|
// caused by fillStackTrace.
|
||||||
|
if (channel.isOpen()) {
|
||||||
|
cause = new NotYetConnectedException();
|
||||||
|
} else {
|
||||||
|
cause = new ClosedChannelException();
|
||||||
|
}
|
||||||
evt.getFuture().setFailure(cause);
|
evt.getFuture().setFailure(cause);
|
||||||
|
|
||||||
fireExceptionCaught(channel, cause);
|
fireExceptionCaught(channel, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
|
Queue<MessageEvent> writeBuffer = channel.writeBufferQueue;
|
||||||
for (;;) {
|
if (!writeBuffer.isEmpty()) {
|
||||||
evt = writeBuffer.poll();
|
// Create the exception only once to avoid the excessive overhead
|
||||||
if (evt == null) {
|
// caused by fillStackTrace.
|
||||||
break;
|
if (cause == null) {
|
||||||
|
if (channel.isOpen()) {
|
||||||
|
cause = new NotYetConnectedException();
|
||||||
|
} else {
|
||||||
|
cause = new ClosedChannelException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
evt = writeBuffer.poll();
|
||||||
|
if (evt == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
evt.getFuture().setFailure(cause);
|
||||||
|
fireExceptionCaught(channel, cause);
|
||||||
}
|
}
|
||||||
evt.getFuture().setFailure(cause);
|
|
||||||
fireExceptionCaught(channel, cause);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -767,6 +792,7 @@ class NioUdpWorker implements Runnable {
|
|||||||
throw new ChannelException(
|
throw new ChannelException(
|
||||||
"Failed to register a socket to the selector.", e);
|
"Failed to register a socket to the selector.", e);
|
||||||
}
|
}
|
||||||
|
// XXX
|
||||||
fireChannelConnected(channel, localAddress);
|
fireChannelConnected(channel, localAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@ import java.net.DatagramPacket;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
|
||||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
|
||||||
import org.jboss.netty.buffer.ChannelBuffers;
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
import org.jboss.netty.channel.Channel;
|
import org.jboss.netty.channel.Channel;
|
||||||
import org.jboss.netty.channel.ChannelFuture;
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
@ -39,8 +38,6 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for {@link NioDatagramChannel}
|
|
||||||
*
|
|
||||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||||
* @author Daniel Bevenius (dbevenius@jboss.com)
|
* @author Daniel Bevenius (dbevenius@jboss.com)
|
||||||
* @version $Rev$, $Date$
|
* @version $Rev$, $Date$
|
||||||
@ -54,7 +51,7 @@ public class NioDatagramChannelTest {
|
|||||||
public static void setupChannel() {
|
public static void setupChannel() {
|
||||||
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
|
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
|
||||||
Executors.newCachedThreadPool());
|
Executors.newCachedThreadPool());
|
||||||
final ServerBootstrap sb = new ServerBootstrap(channelFactory);
|
final ConnectionlessBootstrap sb = new ConnectionlessBootstrap(channelFactory);
|
||||||
inetSocketAddress = new InetSocketAddress("localhost", 9999);
|
inetSocketAddress = new InetSocketAddress("localhost", 9999);
|
||||||
sc = sb.bind(inetSocketAddress);
|
sc = sb.bind(inetSocketAddress);
|
||||||
final SimpleHandler handler = new SimpleHandler();
|
final SimpleHandler handler = new SimpleHandler();
|
||||||
@ -85,7 +82,7 @@ public class NioDatagramChannelTest {
|
|||||||
public void clientBootstrap() {
|
public void clientBootstrap() {
|
||||||
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
|
final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory(
|
||||||
Executors.newCachedThreadPool());
|
Executors.newCachedThreadPool());
|
||||||
final ClientBootstrap bootstrap = new ClientBootstrap(channelFactory);
|
final ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(channelFactory);
|
||||||
bootstrap.getPipeline().addLast("test", new SimpleHandler());
|
bootstrap.getPipeline().addLast("test", new SimpleHandler());
|
||||||
bootstrap.setOption("tcpNoDelay", true);
|
bootstrap.setOption("tcpNoDelay", true);
|
||||||
bootstrap.setOption("keepAlive", true);
|
bootstrap.setOption("keepAlive", true);
|
||||||
|
Loading…
Reference in New Issue
Block a user