[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]netty发送大包超时,channelRead和channelReadComplete的区别

上一篇:[备忘]nexus上传报Error code 400, Bad Request问题
下一篇:[备忘]java序列化和反序列化时,替换包名

添加日期:2021/4/9 18:59:43 快速返回   返回列表 阅读950次
(1)没有解包器,可能是这样的。
--------------------------------------
channelRead收到字节流:1024
channelRead收到字节流:1024
channelRead收到字节流:1024
channelRead收到字节流:1024
channelRead收到字节流:656
channelReadComplete....

channelRead收到字节流:2920
channelReadComplete....

channelRead收到字节流:4096
channelRead收到字节流:284
channelReadComplete....
--------------------------------
从缓冲区,读取一些数据,就触发一次Read方法。
读光了,触发channelReadComplete方法。
即使,发送的是超级大包,也会不断的触发Read方法。

(2)有解包器,可能是这样的:
------------------------------------------
channelReadComplete....
channelReadComplete....
channelReadComplete....
channelReadComplete....
channelReadComplete....
channelReadComplete....
channelRead收到字节流:495837

channelReadComplete....
channelRead收到字节流:579
channelRead收到字节流:166
------------------------------------------
读光了,触发channelReadComplete方法。这个一样。
解出的每个消息都触发一次Read方法。
对于大包,需要channelReadComplete多次,才会收到一个消息,才触发一次Read方法。
对于小包,可能一次channelReadComplete,就包含了多个消息,触发多次Read方法。

(3)前提,有解包器。开始用的netty-all-4.0.27.Final,
ReadTimeoutHandler类里:channelRead方法里会更新lastReadTime。
当传输大包时,可能需要几分钟才收完一个大包,才会触发Read方法。
最终导致触发Read超时事件。
从netty-all-4.0.29.Final版本开始,netty改成了channelReadComplete方法里更新lastReadTime,就没有问题了。
注意:
netty-all-4.1.36.Final.jar里,又不一样。
channelReadComplete里只有第一次read时才更新时间
 


    public void channelReadComplete(ChannelHandlerContext ctx)
        throws Exception
    {
        if((readerIdleTimeNanos > 0L || allIdleTimeNanos > 0L) && reading)
        {
            lastReadTime = ticksInNanos();
            reading = false;
        }
        ctx.fireChannelReadComplete();
    }


具体哪个版本开始变成这样的,没有去追究。

(4)别人的解释:
当channel上面有数据到来时会触发channelRead事件,当数据到来时,eventLoop被唤醒继而调用channelRead方法处理数据。

channelReadComplete事件参考 How does netty determine when a read is complete?
大致意思是eventLoop被到来的数据唤醒后read数据并包装成msg,然后将msg作为参数调用channelRead方法,期间做个判断,read到0个字节或者是read到的字节数小于buffer的容量,满足以上条件就会调用channelReadComplete方法
==================================================
补记:
其实,上述打包超时的原因,是因为ReadTimeoutHandler放在了拆包器后面,如果放在前面就没有问题了。
(1)在AbstractNioByteChannel的read()方法中
------------------------------------
do {
  ...
  pipeline.fireChannelRead(byteBuf);
  ..
} while (++ messages < maxMessagesPerRead);

pipeline.fireChannelReadComplete();
比如每次读1024字节,最后触发complete,这个跟现象是一致的。
没有拆包器,就是先read,后complete。
有拆包器,大包是先complete,后read,小包反之。

(2)拆包器都是ByteToMessageDecoder的子类,在它的channelRead方法里,
会调用decode方法转换消息,然后对结果
for(int i = 0; i < size; ++i) {
     ctx.fireChannelRead(out.get(i));
}
遍历触发read方法。
 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved