- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
当缓冲区大小增加到超过默认值和/或选择了不正确的覆盖位置时,Netty 似乎会降低上传/下载速度(option
或 childOption
) 在 ServerBootStrap 对象中。当连接具有更大的延迟(~300 毫秒)时,这变得更加明显
设置:
Netty 客户端在 MacOS 上并且只有默认值。使用具有 300 毫秒 DNS 延迟的“网络链接调节器”。默认值:SendBuffer/ReceiveBuffer/LowWaterMark/HighWaterMark - 128KB/128KB/32KB/64KB。
Netty 服务器在 Windows 8.1 上,默认值为 SendBuffer/ReceiveBuffer/LowWaterMark/HighWaterMark - 64KB/64KB/32KB/64KB。
Netty 4.1.6 最终版。
使用带有设置的 IO 图使用 wireshark 测量速度:Y 轴 -> SUM(Y 字段),Y 字段 -> tcp.len
设备在本地网络上。
结果(速度值):
服务器->客户端传输(将SO_SNDBUF和水印低/高值设置为0.5*SO_SNDBUF/SO_SNDBUF):
Setting location\SO_SNDBUF | 64KB | 128KB | 1024KB
-----------------------------------------------------------------
option | 3.6MB/s| 3.6MB/s| 3.6MB/s
childOption | 0.2MB/s| 0.5MB/s| 3.6MB/s
客户端->服务器传输(设置SO_RCVBUF):
Setting location\SO_RCVBUF | 64KB | 128KB | 1024KB
-----------------------------------------------------------------
option | 0.2MB/s| 0.5MB/s| 3.6MB/s
childOption | 3.6MB/s| 0.4MB/s| 3.6MB/s
服务器代码:
“参数”值:
“sendToClient”/“sendToServer”(隐式)用于传输方向。覆盖类型的“选项”/“childOption”。“1”/“2”/“3”表示缓冲区值。
ObjectEchoServer.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
public final class ObjectEchoServer {
static final int PORT = 8007;
public static void main(String[] args) throws Exception {
int rcvBuf, sndBuf, lowWaterMark, highWaterMark;
rcvBuf = sndBuf = lowWaterMark = highWaterMark = 0;
switch (args[2]){
case "1":
rcvBuf = 64;
sndBuf = 64;
lowWaterMark = 32;
highWaterMark = 64;
break;
case "2":
rcvBuf = 128;
sndBuf = 128;
lowWaterMark = 64;
highWaterMark = 128;
break;
case "3":
rcvBuf = 1024;
sndBuf = 1024;
lowWaterMark = 512;
highWaterMark = 1024;
break;
}
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoServerHandler(args[0]));
}
});
if(args[1].equalsIgnoreCase("childOption")) {
b.childOption(ChannelOption.SO_RCVBUF, rcvBuf * 1024);
b.childOption(ChannelOption.SO_SNDBUF, sndBuf * 1024);
b.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(lowWaterMark * 1024, highWaterMark * 1024));
} else if(args[1].equalsIgnoreCase("option")){
b.option(ChannelOption.SO_RCVBUF, rcvBuf * 1024);
b.option(ChannelOption.SO_SNDBUF, sndBuf * 1024);
b.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(lowWaterMark * 1024, highWaterMark * 1024));
}
// Bind and start to accept incoming connections.
b.bind(PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
ObjectEchoServerHandler.java
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ObjectEchoServerHandler extends ChannelInboundHandlerAdapter {
private Object msg;
ChannelHandlerContext ctx;
String sendToClient;
public ObjectEchoServerHandler(String sendToClient){
this.sendToClient = sendToClient;
}
@Override
public void channelActive(ChannelHandlerContext ctx){
this.ctx = ctx;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if(sendToClient.equalsIgnoreCase("sendToClient")) {//send a data stream to server
this.msg = msg;
ctx.writeAndFlush(msg).addListener(trafficGenerator);
} //else receive a data stream from client
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
ctx.writeAndFlush(msg).addListener(trafficGenerator);
} else {
future.cause().printStackTrace();
future.channel().close();
}
}
};
}
客户端代码:
“参数”值:
传输方向的“sendToClient”/“sendToServer”(隐式)。
ObjectEchoClient.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
public final class ObjectEchoClient {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = 8007;
static final int SIZE = 256;
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoClientHandler(args[0]));
System.out.println("senbuf:"+ ch.config().getSendBufferSize());
System.out.println("waterhigh:"+ ch.config().getWriteBufferWaterMark().high());
System.out.println("waterlow:"+ ch.config().getWriteBufferWaterMark().low());
System.out.println("recbuf:"+ ch.config().getReceiveBufferSize());
}
});
// Start the connection attempt.
b.connect(HOST, PORT).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
ObjectEchoClientHandler.java
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.ArrayList;
import java.util.List;
public class ObjectEchoClientHandler extends ChannelInboundHandlerAdapter {
private final List<String> firstMessage;
private ChannelHandlerContext ctx;
private String sendToClient;
ObjectEchoClientHandler(String sendToClient) {
this.sendToClient = sendToClient;
firstMessage = new ArrayList<>(ObjectEchoClient.SIZE);
for (int i = 0; i < ObjectEchoClient.SIZE; i++) {
firstMessage.add(Integer.toString(i));
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
this.ctx = ctx;
if(sendToClient.equalsIgnoreCase("sendToClient")) {//get a data stream from server
this.ctx.writeAndFlush(firstMessage);
} else {//send a stream of to server
this.ctx.writeAndFlush(firstMessage).addListener(trafficGenerator);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.flush();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private final ChannelFutureListener trafficGenerator = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
ctx.writeAndFlush(firstMessage).addListener(trafficGenerator);
} else {
future.cause().printStackTrace();
future.channel().close();
}
}
};
}
大问题:
设置缓冲区的正确方法/位置是什么?我找到的信息(主要是代码示例)到处都是。
一个线程(What is the difference between ServerBootstrap.option() and ServerBootstrap.childOption() in netty 4.x)说 ServerBootStrap.childOption
应该用于每个客户端信息,所以我认为两个缓冲区都应该在 ServerBootStrap.childOption
.
最佳答案
我认为这是对的b.option(ChannelOption.SO_RCVBUF, rcvBuf * 1024);
b.option(ChannelOption.SO_SNDBUF, sndBuf * 1024);
关于java - Netty ServerBootStrap 选项或 childOption 及其缓冲区大小对速度的影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41463493/
我要复活this一和Manish Maheshwari的回答,尤其是。哪里有文件证明 The handler, which is defined in the AbstractBootstrap is
根据文档 New and noteworthy in 4.0 ,netty4提供了一个新的bootstrap API,文档给出了如下代码示例: public static void main(Stri
我有一个 ServerBootstrap,配置了相当标准的 Http-Codec ChannelInitializer。 关闭时,我的服务器会等待一段宽限期,在此期间它仍然可以处理传入请求。我的服务器
我有一个基于 netty 的应用程序,它监听多个 tcp 端口。所以每个端口都是这样初始化的 bootstrap = new ServerBootstrap(new NioServerSocketCh
首先,这是我在哪里阅读我现在所知道的关于这个问题的所有内容的引用:http://docs.jboss.org/netty/3.2/api/org/jboss/netty/bootstrap/Serve
我目前不知道如何在多个地址/端口上使用 netty 进行监听。我想构建一个服务于特殊应用程序的小型 HTTP 服务器。我需要在多个地址(如 IPv4 和 IPv6)和端口(443/80)上运行它。 对
我正在尝试使用 Netty (4.0.24) 在一个应用程序(一种主要方法)中创建多个服务器(多个 ServerBootstrap)。我看到了这个问题/答案,但它留下了许多 Unresolved 问题
当缓冲区大小增加到超过默认值和/或选择了不正确的覆盖位置时,Netty 似乎会降低上传/下载速度(option 或 childOption ) 在 ServerBootStrap 对象中。当连接具有更
我正在尝试弄清楚如何最好地获取指向由我的服务器引导生成的 channel 的指针。这个想法是我以后可能会做类似的事情 childChannel.write(x); 这是我目前拥有的代码。 Ev
我是 Netty 的新手。我感到困惑的一件事是 ServerBootstrap 有两种方法:继承自 AbstractBootstrap 的处理程序(ChannelHandler c)和 childHa
我是一名优秀的程序员,十分优秀!