亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

NETTY源碼學習-DELIMITERBASEDFRAMEDECODER

系統 1786 0

看DelimiterBasedFrameDecoder的API,有舉例:

接收到的ChannelBuffer如下:

     +--------------+

 | ABC\nDEF\r\n |

 +--------------+
  

經過DelimiterBasedFrameDecoder(Delimiters.lineDelimiter())之后,得到:

     +-----+-----+

 | ABC | DEF |

 +-----+-----+
  

而不是

     +----------+

 | ABC\nDEF |
  

為什么 ?

首先要明確,如果不指定,DelimiterBasedFrameDecoder默認會去掉分隔符

其次看看Delimiters.lineDelimiter(),它返回兩組delimiter,分別對應 windows linux 的換行符

???

     public static ChannelBuffer[] lineDelimiter() {

        return new ChannelBuffer[] {

                ChannelBuffers.wrappedBuffer(new byte[] { '\r', '\n' }),

                ChannelBuffers.wrappedBuffer(new byte[] { '\n' }),

        };

    }
  

考察這兩組分隔符

方案一

采用“\r\n”作為分隔,則返回

frameA = “ABC\nDEF”

方案二

采用“\n”返回

frameB_0 = “ABC”

frameB_1 = “DEF\r”

由于frameB_0的長度比frameA短,因此在這個例子中,會采用方案二

但有個問題,為什么不是比較全部,而是只比較frameB_0?

要知道,length(frameA) = length(frameB_0) + length(frameB_1),兩者相等

剛開始,我還以為跟split一樣,方案二會一次性返回“ABCDEF\r”

實際上不是

它是遇到一個分隔符,就返回一個結果

可以通過下面的代碼證明:

    public class ClientHandler extends SimpleChannelUpstreamHandler {

    @Override

    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)

            throws Exception {

        String msg = "ABC\nDEF\r\n";

        ChannelBuffer buff = ChannelBuffers.buffer(msg.length());

        buff.writeBytes(msg.getBytes());

        e.getChannel().write(buff);

    }

}


  

Server:

??????

     bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            public ChannelPipeline getPipeline() throws Exception {

                ChannelPipeline pipeline = Channels.pipeline();

				

				//這里設置:不刪除分隔符,方便觀察

                pipeline.addLast("handler1", new DelimiterBasedFrameDecoder(8192, false, Delimiters.lineDelimiter()));

                pipeline.addLast("handler2", new ServerStringHandler());		//
    
      
        打印
      
      decode后的結果

                return pipeline;

            }

        });
    
  

ServerStringHandler:

    public class ServerStringHandler extends SimpleChannelUpstreamHandler{



    @Override

    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)

            throws Exception {

        ChannelBuffer buff = (ChannelBuffer)e.getMessage();

        String msg = (String)buff.toString(Helper.CHARSET_UTF8);

        

        //String s = "abc\n"; 則msg_escape 會原樣輸出“abc\n”,而不是“abc”外加一個換行

        String msg_escape = StringEscapeUtils.escapeJava(msg);  

        System.out.println("msg = " + msg_escape);

    }

}	
  

結果ServerStringHandler會分兩次輸出:

    msg = ABC\n

msg = DEF\r\n
  

查看源碼,會更清楚:

    public class DelimiterBasedFrameDecoder extends FrameDecoder {



    private final ChannelBuffer[] delimiters;

    private final int maxFrameLength;

	

	/*返回結果中,是否去掉分隔符

	通常的調用是去掉分隔符,例如

	new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())

	等價于

	new DelimiterBasedFrameDecoder(8192, /*stripDelimiter=*/true, Delimiters.lineDelimiter())

	*/

    private final boolean stripDelimiter;	

	

	@Override

    protected Object decode(

            ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {

        // Try all delimiters and choose the delimiter which yields the shortest frame.

        int minFrameLength = Integer.MAX_VALUE;

        ChannelBuffer minDelim = null;

		

		/*迭代每一個delimiter,都嘗試進行decode,

		然后選擇返回“shortest frame”的那個delimiter

		重點在indexOf這個方法

		*/

        for (ChannelBuffer delim: delimiters) {

            int frameLength = indexOf(buffer, delim);

            if (frameLength >= 0 && frameLength < minFrameLength) {

                minFrameLength = frameLength;

                minDelim = delim;

            }

        }



        if (minDelim != null) {

            int minDelimLength = minDelim.capacity();

            ChannelBuffer frame;

            if (stripDelimiter) {

                frame = buffer.readBytes(minFrameLength);

                buffer.skipBytes(minDelimLength);

            } else {

                frame = buffer.readBytes(minFrameLength + minDelimLength);

            }



            return frame;

        }

    }

	

	/*

	對frame(haystack)進行搜索,找到第一個delimiter(needle),這個位置記為i

	返回 (i - haystack.readerIndex),也就是分隔后第一個sub frame的長度

	可以看到,它是“找到一個,就返回一個”

	*/

	private static int indexOf(ChannelBuffer haystack, ChannelBuffer needle) {

		//遍歷haystack的每一個字節

        for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {

            int haystackIndex = i;

            int needleIndex;

			

			/*haystack是否出現了delimiter,注意delimiter是一個ChannelBuffer(byte[])

			例如對于haystack="ABC\r\nDEF",needle="\r\n"

			那么當haystackIndex=3時,找到了“\r”,此時needleIndex=0

			繼續執行循環,haystackIndex++,needleIndex++,

			找到了“\n”

			至此,整個needle都匹配到了

			程序然后執行到if (needleIndex == needle.capacity()),返回結果

			*/

            for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {

                if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {

                    break;

                } else {

                    haystackIndex ++;

                    if (haystackIndex == haystack.writerIndex() &&

                        needleIndex != needle.capacity() - 1) {

                        return -1;

                    }

                }

            }



            if (needleIndex == needle.capacity()) {

                // Found the needle from the haystack!

                return i - haystack.readerIndex();

            }

        }

        return -1;

    }



	

}
    

================================================
轉載點別的

? ? 我們首先來看DelimiterBasedFrameDecoder的實現,個人認為這個類實現的真的很牛,有些變量的含義作者沒有增加注釋,有時候可能不容易猜到意圖。首先我們來看一下這個類的成員變量:

?

  1. private? final?ChannelBuffer[]?delimiters;??
  2. ??? private? final? int?maxFrameLength;??
  3. ??? private? final? boolean?stripDelimiter;??
  4. ??? private? final? boolean?failFast;??
  5. ??? private? boolean?discardingTooLongFrame;??
  6. ??? private? int?tooLongFrameLength;??

?

  • delimiters比較好理解,應該就是這個可以接受多個分割符
  • maxFrameLength這個是最大幀的length
  • stripDelimiter這個也很好理解,是否跳過分隔符,就是最終解碼的數據里面是否包含分隔符
  • failFast 為true是說發現讀到的數據已經超過了maxFrameLength了,立即報TooLongFrameException,如果為false就是讀完整個幀數據后再報
  • discardingTooLongFrame 這個是最難理解的,含義是當前的解碼器是否處于discardingTooLongFrame狀態,這個參數最容易理解為是否丟棄tooLongFrame,這個是一個標志位,在構造函數里面是不能進行設置的,只能是解碼器進行設置
  • tooLongFrameLength這個也是一個狀態屬性,就是說出現了超長幀了,哪這個幀的長度到底是多少,就是這個長度,一般來說是在發現當前buffer的可讀數據超過最大幀時候進行設置

? ? ? ??好,看完這個東東后我們就來看一下它的實現:

? ? ? ?我們就來看一下最長的這個構造函數吧:

? ? ? ??

  1. public?DelimiterBasedFrameDecoder(??
  2. ??????????? int?maxFrameLength,? boolean?stripDelimiter,? boolean?failFast,?ChannelBuffer...?delimiters)?{??
  3. ???????validateMaxFrameLength(maxFrameLength);??
  4. ??????? if?(delimiters?==? null)?{??
  5. ??????????? throw? new?NullPointerException( "delimiters");??
  6. ???????}??
  7. ??????? if?(delimiters.length?==? 0)?{??
  8. ??????????? throw? new?IllegalArgumentException( "empty?delimiters");??
  9. ???????}??
  10. ??????? this.delimiters?=? new?ChannelBuffer[delimiters.length];??
  11. ??????? for?( int?i?=? 0;?i?<?delimiters.length;?i?++)?{??
  12. ???????????ChannelBuffer?d?=?delimiters[i];??
  13. ???????????validateDelimiter(d);??
  14. ??????????? this.delimiters[i]?=?d.slice(d.readerIndex(),?d.readableBytes());??
  15. ???????}??
  16. ??????? this.maxFrameLength?=?maxFrameLength;??
  17. ??????? this.stripDelimiter?=?stripDelimiter;??
  18. ??????? this.failFast?=?failFast;??
  19. ???}??

? ??? ? 這個里面我們發現就是如果傳遞多個delimiter的時候,在這個進行了一個slice操作,沒有什么特別的。

? ? ? ?下來我們來看一下最關鍵的decode方法吧:

? ? ? ??

  1. @Override??
  2. ???? protected?Object?decode(??
  3. ????????????ChannelHandlerContext?ctx,?Channel?channel,?ChannelBuffer?buffer)? throws?Exception?{??
  4. ???????? //?Try?all?delimiters?and?choose?the?delimiter?which?yields?the?shortest?frame.??
  5. ???????? int?minFrameLength?=?Integer.MAX_VALUE;??
  6. ????????ChannelBuffer?minDelim?=? null;??
  7. ???????? for?(ChannelBuffer?delim:?delimiters)?{??
  8. ???????????? int?frameLength?=?indexOf(buffer,?delim);??
  9. ???????????? if?(frameLength?>=? 0?&&?frameLength?<?minFrameLength)?{??
  10. ????????????????minFrameLength?=?frameLength;??
  11. ????????????????minDelim?=?delim;??
  12. ????????????}??
  13. ????????}??
  14. ??
  15. ???????? if?(minDelim?!=? null)?{??
  16. ???????????? int?minDelimLength?=?minDelim.capacity();??
  17. ????????????ChannelBuffer?frame;??
  18. ??
  19. ???????????? if?(discardingTooLongFrame)?{??
  20. ???????????????? //?We've?just?finished?discarding?a?very?large?frame.??
  21. ???????????????? //?Go?back?to?the?initial?state.??
  22. ????????????????discardingTooLongFrame?=? false;??
  23. ????????????????buffer.skipBytes(minFrameLength?+?minDelimLength);??
  24. ??
  25. ???????????????? int?tooLongFrameLength?=? this.tooLongFrameLength;??
  26. ???????????????? this.tooLongFrameLength?=? 0;??
  27. ???????????????? if?(!failFast)?{??
  28. ????????????????????fail(ctx,?tooLongFrameLength);??
  29. ????????????????}??
  30. ???????????????? return? null;??
  31. ????????????}??
  32. ??
  33. ???????????? if?(minFrameLength?>?maxFrameLength)?{??
  34. ???????????????? //?Discard?read?frame.??
  35. ????????????????buffer.skipBytes(minFrameLength?+?minDelimLength);??
  36. ????????????????fail(ctx,?minFrameLength);??
  37. ???????????????? return? null;??
  38. ????????????}??
  39. ??
  40. ???????????? if?(stripDelimiter)?{??
  41. ????????????????frame?=?buffer.readBytes(minFrameLength);??
  42. ????????????????buffer.skipBytes(minDelimLength);??
  43. ????????????}? else?{??
  44. ????????????????frame?=?buffer.readBytes(minFrameLength?+?minDelimLength);??
  45. ????????????}??
  46. ??
  47. ???????????? return?frame;??
  48. ????????}? else?{??
  49. ???????????? if?(!discardingTooLongFrame)?{??
  50. ???????????????? if?(buffer.readableBytes()?>?maxFrameLength)?{??
  51. ???????????????????? //?Discard?the?content?of?the?buffer?until?a?delimiter?is?found.??
  52. ????????????????????tooLongFrameLength?=?buffer.readableBytes();??
  53. ????????????????????buffer.skipBytes(buffer.readableBytes());??
  54. ????????????????????discardingTooLongFrame?=? true;??
  55. ???????????????????? if?(failFast)?{??
  56. ????????????????????????fail(ctx,?tooLongFrameLength);??
  57. ????????????????????}??
  58. ????????????????}??
  59. ????????????}? else?{??
  60. ???????????????? //?Still?discarding?the?buffer?since?a?delimiter?is?not?found.??
  61. ????????????????tooLongFrameLength?+=?buffer.readableBytes();??
  62. ????????????????buffer.skipBytes(buffer.readableBytes());??
  63. ????????????}??
  64. ???????????? return? null;??
  65. ????????}??
  66. ????}??

? ? ? ? ??我們慢慢的來看這個代碼的實現,作者為了實現failfast做了很多努力。首先我們看到最開始的代碼就發現,最上面實際上是嘗試所有的分隔符,然后找出一個可用將幀分割最小的一個分割符出來,下面就是if和else,我們先來看if的邏輯:

  • ? 如果找到了分割符,如果當前的解碼器處于discardingTooLongFrame狀態,也就是說上次解碼的時候發現了超長幀,被拋棄過。首先將這個狀態修改過來,標志為不是拋棄過超長幀,這個時候將整個幀丟棄掉,然后如果不是failfast狀態,拋出異常,這個怎么理解呢,可以理解為上次在讀取的時候發現了超長幀,但是由于設置了不立即拋出異常,而是等讀完整個幀數據才拋出異常,這個時候既然發現了分隔符,該到拋出異常的時候了,最后return null表明此次分幀是失敗狀態。
  • 如果發現此次的幀數據超過最大幀的長度,直接拋出異常
  • 最后就是如果跳過分隔符,就直接跳過,負責就和分隔符和幀的實際數據一塊返回

? ? ??else的邏輯是當前讀到的數據沒有發現分隔符的情況下的邏輯,我們來看下:

  • ?如果發現當前的解碼器不是處于discardingTooLongFrame狀態,當前buffer里面的可讀數據又比最大幀要大,我們就將解碼器標記為discardingTooLongFrame狀態,并設置這個超長幀的大小,如果是failfast狀態,就立馬拋出異常,也就是說我們發現了超長幀了,所以我們立馬拋出異常
  • 如果發現當前的解碼器已經處于discardingTooLongFrame狀態,我們別無他方,只能修改下tooLongFrameLength的長度,然后聽天由命,等待下次解碼操作
  • 這個時候如果一旦發現了超長幀,都return null,含義就是說此次解碼是無效的

? ? ? ? 最后我們來看一下indexOf的實現吧,這個很簡單,其實思想和在字符串中找子串的思想是一致的,就不多講解了,自己上代碼:

? ? ? ? ?

  1. private? static? int?indexOf(ChannelBuffer?haystack,?ChannelBuffer?needle)?{??
  2. ???????? for?( int?i?=?haystack.readerIndex();?i?<?haystack.writerIndex();?i?++)?{??
  3. ???????????? int?haystackIndex?=?i;??
  4. ???????????? int?needleIndex;??
  5. ???????????? for?(needleIndex?=? 0;?needleIndex?<?needle.capacity();?needleIndex?++)?{??
  6. ???????????????? if?(haystack.getByte(haystackIndex)?!=?needle.getByte(needleIndex))?{??
  7. ???????????????????? break;??
  8. ????????????????}? else?{??
  9. ????????????????????haystackIndex?++;??
  10. ???????????????????? if?(haystackIndex?==?haystack.writerIndex()?&&??
  11. ????????????????????????needleIndex?!=?needle.capacity()?-? 1)?{??
  12. ???????????????????????? return?- 1;??
  13. ????????????????????}??
  14. ????????????????}??
  15. ????????????}??
  16. ??
  17. ???????????? if?(needleIndex?==?needle.capacity())?{??
  18. ???????????????? //?Found?the?needle?from?the?haystack!??
  19. ???????????????? return?i?-?haystack.readerIndex();??
  20. ????????????}??
  21. ????????}??
  22. ???????? return?- 1;??
  23. ????} ?

NETTY源碼學習-DELIMITERBASEDFRAMEDECODER


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产香蕉尹人综合在线 | 国产午夜精品一区二区三区嫩草 | 欧洲黄色毛片 | 亚洲精品 国产 日韩 | 亚洲 欧美 日韩 在线 香蕉 | 国产a v高清一区二区三区 | 久久国产乱子伦免费精品 | 国内自拍在线观看 | 精品国产三级v | 极品福利在线 | 国产激情一级毛片久久久 | 国产视频在线一区 | 国产精品久热 | 国产在线精品网址你懂的 | 国产精品亚洲一区二区三区久久 | 国产综合在线播放 | 有色视频在线观看免费高清 | 日本高清不卡视频 | 伊人网五月天 | 天天干天天插天天 | 国产精品美女视频 | 色综合久久久 | 26uuu久久| 久久国产乱子伦精品免费一 | 日本一区二区在线播放 | 中文字幕欧美日韩高清 | 国产午夜精品福利 | 久久精品亚瑟全部免费观看 | 美女羞羞免费网站 | 美女久久久久久 | 中文字幕在线最新在线不卡 | 99视频在线永久免费观看 | 久久午夜青青草原影院 | 久久riav国产精品 | 精品日韩在线视频一区二区三区 | 精品无人区乱码1区2区3区在线 | 韩国亚洲伊人久久综合影院 | 91手机视频在线 | 九九影院 影片 | 国产亚洲精品欧美一区 | 色吧色吧色吧网 |