本文介绍了了解网络通道缓冲区和水印的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解Netty缓冲区和水印.

I am trying to understand netty buffers and watermarks.

作为一个测试用例,我有一个写给客户端的Netty服务器,客户端被阻止(每次读取之间的睡眠时间基本上为10秒)

As a test case, I have a netty server which writes to a client, the client is blocked (essentially has a sleep of 10 seconds between each read)

  • 在正常的I/O情况下,如果接收器被阻塞,则TCP发送器将受到限制(由于流量控制,发送速度会变慢),在这种情况下情况并非如此.发件人似乎在每次发送时都不断写入和刷新数据.该数据写在哪里? Netty的flush()中也将有Flow control吗?请参阅: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control

  • Under normal I/O TCP sender would be throttled (sending is slowed down because of flow control) if the receiver is blocked, this is not the case here. The sender seems to keep writing and flushing data on each send. Where is this data being written? Is there going to be Flow control in the netty's flush() as well?See: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control

是否正在将其写入OS或TCP缓冲区,netty通道也具有内部缓冲区吗?如果可以,该如何配置?

Is it is being written to an OS or TCP buffer, does netty channel have an internal buffer as well? If so how can I configure it?

我跟踪bytesBeforeUnwritable,但它们似乎并没有减少

I track bytesBeforeUnwritable but they do not seem to be decreasing

以下代码:

@Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {

        if (server2OutboundChannel.isActive()) {
            if(server2OutboundChannel.isWritable()) {
                server2OutboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {
                            // was able to flush out data, start to read the next chunk
                            //System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
                            ctx.channel().read();
                        } else {
                            future.channel().close();
                        }
                    }
                });
            }else{
                System.out.println("Channel is no longer writeable");
                System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
                System.out.println(server2OutboundChannel.bytesBeforeWritable());
            }
        }
    }

使用端到端源代码重新创建的详细步骤:

Detailed steps to re-create with end-to-end source code:

具体地说,代理代码在这里:

Specifically, the proxy code is here:

https://github.com/nipunarora/nettyDuplicator/tree/master/src/main/java/org/columbia/parikshan/proxy

  • 编译并构建:

  • Compile and Build:

mvn package

启动服务器

sh scripts/Server.sh 3380

启动Netty代理

sh scripts/nettyProxy.sh -l 0.0.0.0:3379 -o 127.0.0.1:3380

启动客户端

sh scripts/Client.sh 127.0.0.1 3379

发送"hello"作为客户端中的std输入

send "hello" as std input in client

netty块在一段时间后发送,并且bytesTillUnwritable不会减少.

netty blocks sending after some time and the bytesTillUnwritable do not decrease.

推荐答案

数据进入ChannelOutboundBuffer.没有像tcp这样的Flow控件.数据将保存在ChannelOutboundBuffer中,直到tcp的发送缓冲区中没有空间为止.

The data went to ChannelOutboundBuffer. There is no Flow control like tcp. The data will be kept in ChannelOutboundBuffer until there is space in tcp's send buffer.

Netty的ChannelOutboundBuffer在发送到OS的缓冲区之前保留数据.您可以按如下所示进行配置.

Netty has ChannelOutboundBuffer which keep data before send to OS'buffer. You can configure it like below.

    Bootstrap bootstrap = new Bootstrap();
    bootstrap.option(ChannelOption.SO_RCVBUF, soRcvBufSize);
    bootstrap.option(ChannelOption.SO_SNDBUF, soSndBufSize);
    bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, writeBufferHighWaterMark);

我编写了示例代码,服务器将其写入被阻止的客户端

I write a sample code that server write to a blocked client

您的代理人的AUTO_READ为假.仅当调用ctx.channel().read()(在将来的侦听器中)时,才会调用NettyProxyFrontendHandler#channelRead. writeAndFlush完成后,将调用该侦听器. writeAndFlush将生成一个任务,并且在将味精写入OS的缓冲区时将完成该任务.如果操作系统的缓冲区已满,任务将被阻止. netty的缓冲区永远不会变为不可写的状态,它始终是可写的.

Your proxy's AUTO_READ is false. NettyProxyFrontendHandler#channelRead will only be called when ctx.channel().read() (in the future listener) is called. The listener will be called after writeAndFlush is completed. writeAndFlush will generate a task and the task will is done when the msg is write to OS's buffer. If OS's buffer is filled, the task will be blocked. There is no chance that netty's buffer will become unwritable, it is always writeable.

您可以在DefaultChannelConfig-> WriteBufferWaterMark.DEFAULT中检查默认水印.当ChannelOutboundBuffer>高水位标记中的数据为isWritable时,返回false,<低水位线返回true.

You can check the defualt water mark in DefaultChannelConfig -> WriteBufferWaterMark.DEFAULT. When data in ChannelOutboundBuffer > high water mark the isWritable return false, < low water mark return true.

 /**
 * Returns {@code true} if and only if the I/O thread will perform the
 * requested write operation immediately.  Any write requests made when
 * this method returns {@code false} are queued until the I/O thread is
 * ready to process the queued write requests.
 */
boolean isWritable();

这篇关于了解网络通道缓冲区和水印的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 05:49