Enable TCP_NODELAY and SCTP_NODELAY by default

- Fixes #939
- Add PlatformDependent.canEnableTcpNoDelayByDefault()
  - Currently returns false on Android. Will change if necessary later.
This commit is contained in:
Trustin Lee 2013-01-31 12:17:09 +09:00
parent 152c969eab
commit 39357f3835
10 changed files with 66 additions and 18 deletions

View File

@ -42,6 +42,8 @@ public final class PlatformDependent {
private static final int JAVA_VERSION = javaVersion0(); private static final int JAVA_VERSION = javaVersion0();
private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid();
private static final boolean HAS_UNSAFE = hasUnsafe0(); private static final boolean HAS_UNSAFE = hasUnsafe0();
private static final boolean CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer0(); private static final boolean CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer0();
private static final boolean IS_UNALIGNED = isUnaligned0(); private static final boolean IS_UNALIGNED = isUnaligned0();
@ -75,6 +77,13 @@ public final class PlatformDependent {
return JAVA_VERSION; return JAVA_VERSION;
} }
/**
* Returns {@code true} if and only if it is fine to enable TCP_NODELAY socket option by default.
*/
public static boolean canEnableTcpNoDelayByDefault() {
return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
}
/** /**
* Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used. * Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used.
*/ */

View File

@ -43,7 +43,6 @@ public class EchoServer {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100) .option(ChannelOption.SO_BACKLOG, 100)
.childOption(ChannelOption.TCP_NODELAY, true)
.handler(new LoggingHandler(LogLevel.INFO)) .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override

View File

@ -53,7 +53,6 @@ public class FileServer {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class) .channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100) .option(ChannelOption.SO_BACKLOG, 100)
.childOption(ChannelOption.TCP_NODELAY, true)
.handler(new LoggingHandler(LogLevel.INFO)) .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() { .childHandler(new ChannelInitializer<SocketChannel>() {
@Override @Override

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.sctp.SctpChannel; import io.netty.channel.sctp.SctpChannel;
import io.netty.channel.sctp.SctpChannelOption;
import io.netty.channel.sctp.nio.NioSctpServerChannel; import io.netty.channel.sctp.nio.NioSctpServerChannel;
import io.netty.channel.socket.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioEventLoopGroup;
import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LogLevel;
@ -44,7 +43,6 @@ public class NioSctpEchoServer {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
.channel(NioSctpServerChannel.class) .channel(NioSctpServerChannel.class)
.option(ChannelOption.SO_BACKLOG, 100) .option(ChannelOption.SO_BACKLOG, 100)
.childOption(SctpChannelOption.SCTP_NODELAY, true)
.handler(new LoggingHandler(LogLevel.INFO)) .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SctpChannel>() { .childHandler(new ChannelInitializer<SctpChannel>() {
@Override @Override

View File

@ -20,7 +20,6 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.sctp.SctpChannel; import io.netty.channel.sctp.SctpChannel;
import io.netty.channel.sctp.SctpChannelOption;
import io.netty.channel.sctp.oio.OioSctpServerChannel; import io.netty.channel.sctp.oio.OioSctpServerChannel;
import io.netty.channel.socket.oio.OioEventLoopGroup; import io.netty.channel.socket.oio.OioEventLoopGroup;
import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LogLevel;
@ -44,7 +43,6 @@ public class OioSctpEchoServer {
b.group(new OioEventLoopGroup(), new OioEventLoopGroup()) b.group(new OioEventLoopGroup(), new OioEventLoopGroup())
.channel(OioSctpServerChannel.class) .channel(OioSctpServerChannel.class)
.option(ChannelOption.SO_BACKLOG, 100) .option(ChannelOption.SO_BACKLOG, 100)
.childOption(SctpChannelOption.SCTP_NODELAY, true)
.handler(new LoggingHandler(LogLevel.INFO)) .handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SctpChannel>() { .childHandler(new ChannelInitializer<SctpChannel>() {
@Override @Override

View File

@ -22,6 +22,7 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.util.internal.PlatformDependent;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -41,6 +42,15 @@ public class DefaultSctpChannelConfig extends DefaultChannelConfig implements Sc
throw new NullPointerException("javaChannel"); throw new NullPointerException("javaChannel");
} }
this.javaChannel = javaChannel; this.javaChannel = javaChannel;
// Enable TCP_NODELAY by default if possible.
if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
try {
setSctpNoDelay(true);
} catch (Exception e) {
// Ignore.
}
}
} }
@Override @Override

View File

@ -46,13 +46,17 @@ public interface SctpChannelConfig extends ChannelConfig {
/** /**
* Gets the <a href="http://openjdk.java.net/projects/sctp/javadoc/com/sun/nio/sctp/SctpStandardSocketOption.html"> * Gets the <a href="http://openjdk.java.net/projects/sctp/javadoc/com/sun/nio/sctp/SctpStandardSocketOption.html">
* {@code SCTP_NODELAY}</a> option. * {@code SCTP_NODELAY}</a> option. Please note that the default value of this option is {@code true} unlike the
* operating system default ({@code false}). However, for some buggy platforms, such as Android, that shows erratic
* behavior with Nagle's algorithm disabled, the default value remains to be {@code false}.
*/ */
boolean isSctpNoDelay(); boolean isSctpNoDelay();
/** /**
* Sets the <a href="http://openjdk.java.net/projects/sctp/javadoc/com/sun/nio/sctp/SctpStandardSocketOption.html"> * Sets the <a href="http://openjdk.java.net/projects/sctp/javadoc/com/sun/nio/sctp/SctpStandardSocketOption.html">
* {@code SCTP_NODELAY}</a> option. * {@code SCTP_NODELAY}</a> option. Please note that the default value of this option is {@code true} unlike the
* operating system default ({@code false}). However, for some buggy platforms, such as Android, that shows erratic
* behavior with Nagle's algorithm disabled, the default value remains to be {@code false}.
*/ */
SctpChannelConfig setSctpNoDelay(boolean sctpNoDelay); SctpChannelConfig setSctpNoDelay(boolean sctpNoDelay);

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.util.internal.PlatformDependent;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
@ -44,6 +45,15 @@ public class DefaultSocketChannelConfig extends DefaultChannelConfig
throw new NullPointerException("javaSocket"); throw new NullPointerException("javaSocket");
} }
this.javaSocket = javaSocket; this.javaSocket = javaSocket;
// Enable TCP_NODELAY by default if possible.
if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
try {
setTcpNoDelay(true);
} catch (Exception e) {
// Ignore.
}
}
} }
@Override @Override

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import java.net.Socket; import java.net.Socket;
import java.net.StandardSocketOptions; import java.net.StandardSocketOptions;
@ -35,33 +36,39 @@ import java.net.StandardSocketOptions;
* <tr> * <tr>
* <th>Name</th><th>Associated setter method</th> * <th>Name</th><th>Associated setter method</th>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#SO_KEEPALIVE}</td><td>{@link #setKeepAlive(boolean)}</td> * <td>{@link ChannelOption#SO_KEEPALIVE}</td><td>{@link #setKeepAlive(boolean)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#SO_REUSEADDR}</td><td>{@link #setReuseAddress(boolean)}</td> * <td>{@link ChannelOption#SO_REUSEADDR}</td><td>{@link #setReuseAddress(boolean)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#SO_LINGER}</td><td>{@link #setSoLinger(int)}</td> * <td>{@link ChannelOption#SO_LINGER}</td><td>{@link #setSoLinger(int)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#TCP_NODELAY}</td><td>{@link #setTcpNoDelay(boolean)}</td> * <td>{@link ChannelOption#TCP_NODELAY}</td><td>{@link #setTcpNoDelay(boolean)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#SO_RCVBUF}</td><td>{@link #setReceiveBufferSize(int)}</td> * <td>{@link ChannelOption#SO_RCVBUF}</td><td>{@link #setReceiveBufferSize(int)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#SO_SNDBUF}</td><td>{@link #setSendBufferSize(int)}</td> * <td>{@link ChannelOption#SO_SNDBUF}</td><td>{@link #setSendBufferSize(int)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#IP_TOS}</td><td>{@link #setTrafficClass(int)}</td> * <td>{@link ChannelOption#IP_TOS}</td><td>{@link #setTrafficClass(int)}</td>
* </tr><tr> * </tr><tr>
* <td>{@link io.netty.channel.ChannelOption#ALLOW_HALF_CLOSURE}</td><td>{@link #setAllowHalfClosure(boolean)}</td> * <td>{@link ChannelOption#ALLOW_HALF_CLOSURE}</td><td>{@link #setAllowHalfClosure(boolean)}</td>
* </tr> * </tr>
* </table> * </table>
*/ */
public interface SocketChannelConfig extends ChannelConfig { public interface SocketChannelConfig extends ChannelConfig {
/** /**
* Gets the {@link StandardSocketOptions#TCP_NODELAY} option. * Gets the {@link StandardSocketOptions#TCP_NODELAY} option. Please note that the default value of this option
* is {@code true} unlike the operating system default ({@code false}). However, for some buggy platforms, such as
* Android, that shows erratic behavior with Nagle's algorithm disabled, the default value remains to be
* {@code false}.
*/ */
boolean isTcpNoDelay(); boolean isTcpNoDelay();
/** /**
* Sets the {@link StandardSocketOptions#TCP_NODELAY} option. * Sets the {@link StandardSocketOptions#TCP_NODELAY} option. Please note that the default value of this option
* is {@code true} unlike the operating system default ({@code false}). However, for some buggy platforms, such as
* Android, that shows erratic behavior with Nagle's algorithm disabled, the default value remains to be
* {@code false}.
*/ */
SocketChannelConfig setTcpNoDelay(boolean tcpNoDelay); SocketChannelConfig setTcpNoDelay(boolean tcpNoDelay);

View File

@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelException; import io.netty.channel.ChannelException;
import io.netty.channel.ChannelOption; import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.util.internal.PlatformDependent;
import java.io.IOException; import java.io.IOException;
import java.net.SocketOption; import java.net.SocketOption;
@ -57,6 +58,7 @@ final class DefaultAioSocketChannelConfig extends DefaultChannelConfig
*/ */
DefaultAioSocketChannelConfig(AioSocketChannel channel) { DefaultAioSocketChannelConfig(AioSocketChannel channel) {
super(channel); super(channel);
enableTcpNoDelay();
} }
/** /**
@ -65,6 +67,18 @@ final class DefaultAioSocketChannelConfig extends DefaultChannelConfig
DefaultAioSocketChannelConfig(AioSocketChannel channel, NetworkChannel javaChannel) { DefaultAioSocketChannelConfig(AioSocketChannel channel, NetworkChannel javaChannel) {
super(channel); super(channel);
this.javaChannel.set(javaChannel); this.javaChannel.set(javaChannel);
enableTcpNoDelay();
}
private void enableTcpNoDelay() {
// Enable TCP_NODELAY by default if possible.
if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
try {
setTcpNoDelay(true);
} catch (Exception e) {
// Ignore.
}
}
} }
@Override @Override