• 学习
    2019-12-08
    老师,handler的顺序那里还是没太懂,为什么两个encodeHandler放在frameDecodeHandler后面呢

    作者回复: 读保证自上而下,写保证自下而上就行了,读与写之间其实顺序无所谓,但是一般为了好看对称,我们是一组一组写。案例中的顺序功能是没有问题的,只是让你产生了疑惑。
    你提出的这个不懂,我觉得我可以改下,但是如果我改了,或许你就没有这个问题了,哈哈,所以我要考虑下好看与教学效果之间做个平衡。

    
     1
  • 夷,这也可以
    2019-11-17
    老师,我问个比较业余的问题,因为你这个案例完全是基于tcp协议来的,所以第一次和第二次编解码也是自定义。客服端和服务端都是必须是同一套编解码。netty对其他协议的支持(http、mqtt等)就是根据消息协议的格式约定,实现数据的第一次和第二次编解码。当然也可能把第一次和第二次统一封装成一个编码类方便api调用。不过底层数据传输走的还是这几个步骤。也就是netty都可以看做4+1的处理方式来实现各种协议的网络传输处理。不知道理解的对不对?

    作者回复: 对于tcp大多如此的,但是有一种情况,就是如果你接受到数据,立马就转走,像路由器一样,那这个时候,你的处理就不需要那么多层次的编解码了,因为你不做处理,只是二转手,就像快递员一样,不会拆你的快递一样,就是给你转走;
    不是这种情况下,大多都需要4+1, 4是2组:1组处理粘包:1组处理转化给用户好用/存储。最后那个1业务处理。

    
     1
  • zpzeng
    2019-11-16
    老师,对于channelHandler是否共享有没有什么一般性原则,判断依据。我感觉demo里Server端的几个Handler都没有对传入的参数引用做保存,修改操作,我觉得并发没问题,那是不是就可以全部都共享。

    作者回复: 你这个感觉很好,我也是这么判断的,除了这点之外,你分2种情况看:别人写的和自己要写的,如果是别人写的,你看它可标记成@sharable了。如果自己写的,自己最清楚了,主要看可有线程安全和是否符合自己的需求,比如你统计整个系统的,一般都要做成共享的,如果你统计单一连接的,你肯定就是非共享的,不管用哪种方式去看,自己去实际分析代码最准确。其中就有你说的那个小方法,就是看那个类可有成员变量,如果一个没有,十有八九都可以共享。

    
     1
  • Gary
    2019-11-14
    老师您好,为什么注册时inboundhandler中夹着outboundhandler,不是先写完inboundhandler再写outboubdhandler?

    作者回复: 这个问题很好,其实是风格问题,你说的那样也可以,但是现在大多都是按照我那样的写法写,因为体现一对一对的感觉,很清晰,如果按照你想要的那种写法,其实让别人看到的是那种业务逻辑处理的感觉了,然后读者还要去读去找,看看你是不是一对一对的了。

     2
     1
  • AAA
    2020-01-02
    老师,handler顺序问题是不是处理请求的时候是顺序处理响应是倒序的,因为处理请求的时候是先拼装消息体再Encode,而处理响应是先Decode再解析消息体,是这样吗?

    作者回复: 你这样说不是割裂了请求处理和响应了么?而且你说的不对吧。
    请求是先解码,解出最终的业务请求,然后执行,然后再编码,作为响应发送回去。
    就像在U型滑道上单向玩板车一样,是一个连续的过程。

    
    
  • 虹炎
    2019-12-31
    老师我问的第三个问题,如果我发送数据的数据长度length写为1000byte,实际传数据100个byte. netty怎么处理这种传输的数据呢? 我第一次发送数据是故意这样做,第二次以后,就发送正确的数据,netty是不是就会报错了,如果用LengthFieldBasedFrameDecoder。netty怎么处理,别人知道协议后,故意发送这种不符合要求的数据攻击呢。

    作者回复: 参考这个实现:io.netty.handler.codec.LengthFieldBasedFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf)

    首先,你这样做,netty不知道你是故意的,所以他认为这个数据还没有传完,所以会等你第二个正确的数据过来的时候,把你第二个数据(或部分,反正一共900字节)合并前面的100字节当第一个数据来处理,说是处理,还是传给你业务层,这个时候,一般你肯定会出错的(比如你做json解析肯定抛异常了),因为这个数据不是完整正确的。所以这个时候下步怎么走,要看你的io.netty.channel.ChannelHandler#exceptionCaught
    怎么实现了。
    这种情况,很难恢复回来了,所以可以直接在这个方法的实现中,直接把连接断掉。

    你后面的问题,所以你要做授权(后面一章的内容)等防范,如果都授权过了。那别人就没有机会来发送这种数据。

    
    
  • 虹炎
    2019-12-28
    1,frame=length,version,opCode,streamld,operation/operation result
    length=version,opCode,streamld,operation/operation result
    我理解length表示version,opCode,streamld,operation/operation result 总字节数。
    我在代码中没有看到length值的设置。还是我理解错了呢?
    2,因为不知到length大小(我理解的发送的数据总字节数),public class OrderFrameDecoder extends LengthFieldBasedFrameDecoder。LengthFieldBasedFrameDecoder类怎么知道数据有没有接收完呢?它应该不知道数据的边界啊。
    3,如果我发送数据的数据长度length写为1000byte,实际传数据100个byte. netty怎么处理这种
    传输的数据呢?
    4,public void encode(ByteBuf byteBuf) {
            byteBuf.writeInt(messageHeader.getVersion());
            byteBuf.writeLong(messageHeader.getStreamId());
            byteBuf.writeInt(messageHeader.getOpCode());
            byteBuf.writeBytes(JsonUtil.toJson(messageBody).getBytes());
        }

        public void decode(ByteBuf msg) {
            int version = msg.readInt();
            long streamId = msg.readLong();
            int opCode = msg.readInt();
            MessageHeader messageHeader = new MessageHeader();
            messageHeader.setVersion(version);
            messageHeader.setOpCode(opCode);
            messageHeader.setStreamId(streamId);
            this.messageHeader = messageHeader;
            Class<T> bodyClazz = getMessageBodyDecodeClass(opCode);
            T body = JsonUtil.fromJson(msg.toString(Charset.forName("UTF-8")), bodyClazz);
            this.messageBody = body;
        }
    老师: JsonUtil.fromJson(msg.toString(Charset.forName("UTF-8")),这里的msg怎么没有包含
    version,streamId,opCode呢。虽然读索引往后走了,我感觉msg应该还是整个ByteBuf啊,包含
    version,streamId,opCode数据。怎么回事呢?怎么反序化就成功了呢?期待老师的解答。
    展开

    作者回复: 1 你的理解对的;
    2 长度体现在OrderFrameDecoder里面,它继承了netty自带的LengthFieldBasedFrameDecoder,能处理长度相关的事情。如果忘记原理,可以参考第二章的粘包、半包那一节再看一遍。
    3 等于半包了,会把数据先buffer下,然后等待后面的900字节,完整后再解析出来。
    4 是整个,但是前面readInt、readLong等已经读走了部分数据,后面的tostring()返回的其实是readable的数据。

     3
    
  • 虹炎
    2019-12-28
    frame=length,version,opCode,streamld,operation/operation result.
    length = version,opCode,streamld,operation/operation result. 通过之前的例子,这里的length不是表示
    version,opCode,streamld,operation/operation result 的总字节长度吗?老师的demo,我没发现length体现在
    哪里啊?求解答。

    作者回复: 体现在OrderFrameDecoder里面,它继承了netty自带的LengthFieldBasedFrameDecoder,能处理长度相关的事情。如果忘记原理,可以参考第二章再看一遍。

    
    
  • 夷,这也可以
    2019-11-21
    有一种情况,就是如果你接受到数据,立马就转走,像路由器一样,那这个时候,你的处理就不需要那么多层次的编解码了,因为你不做处理,只是二转手,就像快递员一样,不会拆你的快递一样,就是给你转走;
    老师这种情况一般是1层编解码还是不需要?我的一个疑问是,路由转发也是有一定规则的,这个规则的判断也是需要对信息识别的,那还是要编解码呀?还是说传输过程中也有类似快递单号那样特殊消息(这个特殊消息是否需要编解码呢?)能帮我们,理解不到位,请老师指教!

    作者回复: 是的,你说的对的,我感觉你很理解了,看需求,比如你不需要根据信息里面的内容做判断(比如),你就直接中转扔出去,但是像快递那个例子,你要看下编号什么的,那就做一层解码,然后扔出去,所以说做几层看业务需求,大多都是二层。

    
    
  • Gary
    2019-11-19
    也许是个人对java刚接触不久,一直从事c++开发的原因,感觉应该从第四章开始学,学完了用法示例再看前面的原理和源码分析效果更好。

    作者回复: 是的,有其他人也反映顺序的设置是否像你说的那样更合理,当时考虑是说netty的案例真的挺简单的,上来直接说,缺乏一点基础的人,肯定觉得很晕,不知道在讲什么,所以就故意把顺序颠倒过来,这样可能更适合新手,但是也出现一些有经验的人,觉得这样的设计没有先案例后原理的好,所以只能建议反过来再看一遍,因为确实有的时候,一次看不明白,就需要翻书对照着看,好在总时长不长,就当复习也可以。

    
    
  • 小不点
    2019-11-18
    呦西,学到了学到了,周三再见了。。。

    作者回复: 你快坚持到底了,哈哈

    
    
  • 十年
    2019-11-15
    老师,请问业务处理层,一般会使用spring管理bean,集成mybatis吗?

    作者回复: 可以的,业务层就是我们自己的业务逻辑了,随便怎么搞都可以。

    
    
  • 鱼向北游
    2019-11-15
    感觉channel.writeandflush也挺常见呀,有时候接的消息为了解耦是直接放队列,然后消费调rpc,等rpc返回的时候一般找的都是channel呀,再用writeandflush写出去,好像那时候就没ctx了

    作者回复: 客户端常见,服务器端见的少些,还是看具体需求,但是一定要搞清楚两者之间区别,否则要不多绕了一圈,要不就搞出问题了。当然有很多时候也不出问题,这里列出来的意思就是让大家要搞清楚这两个不一样,写的时候,小心点,如果用好了,能节约调用。

    
    
  • 吃饭饭
    2019-11-13
    有个地方不明白:我们自定义的消息包含 Body 和 Header,为了解决粘包和半包需要添加一个 Length 字段,但是我没找到处理这个实际处理的地方呢,难道仅仅设置一个 lengthFieldLength = 2 就可以实现解析自定义的消息吗?

    作者回复: 是的,处理的逻辑在netty自己的类里面:LengthFieldBasedFrameDecoder,可以回看12-13节内容。参考io.netty.handler.codec.LengthFieldBasedFrameDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf)

    
    
我们在线,来聊聊吧