diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index fa28ddceb0..d856a5ea4f 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -42,6 +42,8 @@ public final class PlatformDependent { 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 CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer0(); private static final boolean IS_UNALIGNED = isUnaligned0(); @@ -75,6 +77,13 @@ public final class PlatformDependent { 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. */ diff --git a/example/src/main/java/io/netty/example/echo/EchoServer.java b/example/src/main/java/io/netty/example/echo/EchoServer.java index efa1b815c3..f8bada30ed 100644 --- a/example/src/main/java/io/netty/example/echo/EchoServer.java +++ b/example/src/main/java/io/netty/example/echo/EchoServer.java @@ -43,7 +43,6 @@ public class EchoServer { b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) - .childOption(ChannelOption.TCP_NODELAY, true) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer() { @Override diff --git a/example/src/main/java/io/netty/example/filetransfer/FileServer.java b/example/src/main/java/io/netty/example/filetransfer/FileServer.java index adf27b8096..d39371470c 100644 --- a/example/src/main/java/io/netty/example/filetransfer/FileServer.java +++ b/example/src/main/java/io/netty/example/filetransfer/FileServer.java @@ -53,7 +53,6 @@ public class FileServer { b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) - .childOption(ChannelOption.TCP_NODELAY, true) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer() { @Override diff --git a/example/src/main/java/io/netty/example/sctp/NioSctpEchoServer.java b/example/src/main/java/io/netty/example/sctp/NioSctpEchoServer.java index 13951fdb86..262eecf891 100644 --- a/example/src/main/java/io/netty/example/sctp/NioSctpEchoServer.java +++ b/example/src/main/java/io/netty/example/sctp/NioSctpEchoServer.java @@ -20,7 +20,6 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.sctp.SctpChannel; -import io.netty.channel.sctp.SctpChannelOption; import io.netty.channel.sctp.nio.NioSctpServerChannel; import io.netty.channel.socket.nio.NioEventLoopGroup; import io.netty.handler.logging.LogLevel; @@ -44,7 +43,6 @@ public class NioSctpEchoServer { b.group(new NioEventLoopGroup(), new NioEventLoopGroup()) .channel(NioSctpServerChannel.class) .option(ChannelOption.SO_BACKLOG, 100) - .childOption(SctpChannelOption.SCTP_NODELAY, true) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer() { @Override diff --git a/example/src/main/java/io/netty/example/sctp/OioSctpEchoServer.java b/example/src/main/java/io/netty/example/sctp/OioSctpEchoServer.java index 84914fceb1..39988278fe 100644 --- a/example/src/main/java/io/netty/example/sctp/OioSctpEchoServer.java +++ b/example/src/main/java/io/netty/example/sctp/OioSctpEchoServer.java @@ -20,7 +20,6 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.sctp.SctpChannel; -import io.netty.channel.sctp.SctpChannelOption; import io.netty.channel.sctp.oio.OioSctpServerChannel; import io.netty.channel.socket.oio.OioEventLoopGroup; import io.netty.handler.logging.LogLevel; @@ -44,7 +43,6 @@ public class OioSctpEchoServer { b.group(new OioEventLoopGroup(), new OioEventLoopGroup()) .channel(OioSctpServerChannel.class) .option(ChannelOption.SO_BACKLOG, 100) - .childOption(SctpChannelOption.SCTP_NODELAY, true) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer() { @Override diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java index 2fec0f2331..86f171960c 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java @@ -22,6 +22,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.util.internal.PlatformDependent; import java.io.IOException; import java.util.Map; @@ -41,6 +42,15 @@ public class DefaultSctpChannelConfig extends DefaultChannelConfig implements Sc throw new NullPointerException("javaChannel"); } this.javaChannel = javaChannel; + + // Enable TCP_NODELAY by default if possible. + if (PlatformDependent.canEnableTcpNoDelayByDefault()) { + try { + setSctpNoDelay(true); + } catch (Exception e) { + // Ignore. + } + } } @Override diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java index d22cded6e2..0d46d79241 100644 --- a/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java @@ -46,13 +46,17 @@ public interface SctpChannelConfig extends ChannelConfig { /** * Gets the - * {@code SCTP_NODELAY} option. + * {@code SCTP_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 isSctpNoDelay(); /** * Sets the - * {@code SCTP_NODELAY} option. + * {@code SCTP_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}. */ SctpChannelConfig setSctpNoDelay(boolean sctpNoDelay); diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java index 4d4d2f4680..20acd25477 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.util.internal.PlatformDependent; import java.net.Socket; import java.net.SocketException; @@ -44,6 +45,15 @@ public class DefaultSocketChannelConfig extends DefaultChannelConfig throw new NullPointerException("javaSocket"); } this.javaSocket = javaSocket; + + // Enable TCP_NODELAY by default if possible. + if (PlatformDependent.canEnableTcpNoDelayByDefault()) { + try { + setTcpNoDelay(true); + } catch (Exception e) { + // Ignore. + } + } } @Override diff --git a/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java index 79f4bdc436..672c703129 100644 --- a/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/SocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOption; import java.net.Socket; import java.net.StandardSocketOptions; @@ -35,33 +36,39 @@ import java.net.StandardSocketOptions; * * NameAssociated setter method * - * {@link io.netty.channel.ChannelOption#SO_KEEPALIVE}{@link #setKeepAlive(boolean)} + * {@link ChannelOption#SO_KEEPALIVE}{@link #setKeepAlive(boolean)} * - * {@link io.netty.channel.ChannelOption#SO_REUSEADDR}{@link #setReuseAddress(boolean)} + * {@link ChannelOption#SO_REUSEADDR}{@link #setReuseAddress(boolean)} * - * {@link io.netty.channel.ChannelOption#SO_LINGER}{@link #setSoLinger(int)} + * {@link ChannelOption#SO_LINGER}{@link #setSoLinger(int)} * - * {@link io.netty.channel.ChannelOption#TCP_NODELAY}{@link #setTcpNoDelay(boolean)} + * {@link ChannelOption#TCP_NODELAY}{@link #setTcpNoDelay(boolean)} * - * {@link io.netty.channel.ChannelOption#SO_RCVBUF}{@link #setReceiveBufferSize(int)} + * {@link ChannelOption#SO_RCVBUF}{@link #setReceiveBufferSize(int)} * - * {@link io.netty.channel.ChannelOption#SO_SNDBUF}{@link #setSendBufferSize(int)} + * {@link ChannelOption#SO_SNDBUF}{@link #setSendBufferSize(int)} * - * {@link io.netty.channel.ChannelOption#IP_TOS}{@link #setTrafficClass(int)} + * {@link ChannelOption#IP_TOS}{@link #setTrafficClass(int)} * - * {@link io.netty.channel.ChannelOption#ALLOW_HALF_CLOSURE}{@link #setAllowHalfClosure(boolean)} + * {@link ChannelOption#ALLOW_HALF_CLOSURE}{@link #setAllowHalfClosure(boolean)} * * */ 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(); /** - * 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); diff --git a/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java index 63a388172f..6a38cabfb3 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/DefaultAioSocketChannelConfig.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; +import io.netty.util.internal.PlatformDependent; import java.io.IOException; import java.net.SocketOption; @@ -57,6 +58,7 @@ final class DefaultAioSocketChannelConfig extends DefaultChannelConfig */ DefaultAioSocketChannelConfig(AioSocketChannel channel) { super(channel); + enableTcpNoDelay(); } /** @@ -65,6 +67,18 @@ final class DefaultAioSocketChannelConfig extends DefaultChannelConfig DefaultAioSocketChannelConfig(AioSocketChannel channel, NetworkChannel javaChannel) { super(channel); 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