成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Netty - 粘包和半包(下)

網絡 網絡管理
上一篇介紹了粘包和半包及其通用的解決方案,今天重點來看一下 Netty 是如何實現封裝成幀(Framing)方案的。

接上篇《TCP 粘包和半包 介紹及解決(上)

上一篇介紹了粘包和半包及其通用的解決方案,今天重點來看一下 Netty 是如何實現封裝成幀(Framing)方案的。

解碼核心流程

之前介紹過三種解碼器FixedLengthFrameDecoder、DelimiterBasedFrameDecoder、LengthFieldBasedFrameDecoder,它們都繼承自ByteToMessageDecoder,而ByteToMessageDecoder繼承自ChannelInboundHandlerAdapter,其核心方法為channelRead。因此,我們來看看ByteToMessageDecoder的channelRead方法:

  1. @Override 
  2. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
  3.  if (msg instanceof ByteBuf) { 
  4.  CodecOutputList out = CodecOutputList.newInstance(); 
  5.  try { 
  6.  // 將傳入的消息轉化為data 
  7.  ByteBuf data = (ByteBuf) msg; 
  8.  // 最終實現的目標是將數據全部放進cumulation中 
  9.  first = cumulation == null; 
  10.  // 第一筆數據直接放入 
  11.  if (first) { 
  12.  cumulation = data
  13.  } else { 
  14.  // 不是第一筆數據就進行追加 
  15.  cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); 
  16.  } 
  17.  // 解碼 
  18.  callDecode(ctx, cumulation, out); 
  19.  } 
  20.  // 以下代碼省略,因為不屬于解碼過程 
  21.  } 

再來看看callDecode方法:

  1. protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { 
  2.  try { 
  3.  while (in.isReadable()) { 
  4.  int outoutSize = out.size(); 
  5.  if (outSize > 0) { 
  6.  // 以下代碼省略,因為初始狀態時,outSize 只可能是0,不可能進入這里 
  7.  } 
  8.  int oldInputLength = in.readableBytes(); 
  9.  // 在進行 decode 時,不執行handler的remove操作。 
  10.  // 只有當 decode 執行完之后,開始清理數據。 
  11.  decodeRemovalReentryProtection(ctx, in, out); 
  12.  // 省略以下代碼,因為后面的內容也不是解碼的過程 

再來看看decodeRemovalReentryProtection方法:

  1. final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) 
  2.  throws Exception { 
  3.  // 設置當前狀態為正在解碼 
  4.  decodeState = STATE_CALLING_CHILD_DECODE
  5.  try { 
  6.  // 解碼 
  7.  decode(ctx, in, out); 
  8.  } finally { 
  9.  // 執行hander的remove操作 
  10.  boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING; 
  11.  decodeState = STATE_INIT
  12.  if (removePending) { 
  13.  handlerRemoved(ctx); 
  14.  } 
  15.  } 
  16. // 子類都重寫了該方法,每種實現都會有自己特殊的解碼方式 
  17. protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception; 

從上面的過程可以總結出,在解碼之前,需要先將數據寫入cumulation,當解碼結束后,需要通過 handler 進行移除。

具體解碼過程

剛剛說到decode方法在子類中都有實現,那針對我們說的三種解碼方式,一一看其實現。

1. FixedLengthFrameDecoder

其源碼為:

  1. @Override 
  2. protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 
  3.  Object decodedecoded = decode(ctx, in); 
  4.  if (decoded != null) { 
  5.  out.add(decoded); 
  6.  } 
  7. protected Object decode( 
  8.  @SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception { 
  9.  // 收集到的數據是否小于固定長度,小于就代表無法解析 
  10.  if (in.readableBytes() < frameLength) { 
  11.  return null; 
  12.  } else { 
  13.  return in.readRetainedSlice(frameLength); 
  14.  } 

就和這個類的名字一樣簡單,就是固定長度進行解碼,因此,在設置該解碼器的時候,需要在構造方式里傳入frameLength。

2. DelimiterBasedFrameDecoder

其源碼為:

  1. @Override 
  2. protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 
  3.  Object decodedecoded = decode(ctx, in); 
  4.  if (decoded != null) { 
  5.  out.add(decoded); 
  6.  } 
  7. protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { 
  8.  // 當前的分割符是否是換行分割符(\n或者\r\n) 
  9.  if (lineBasedDecoder != null) { 
  10.  return lineBasedDecoder.decode(ctx, buffer); 
  11.  } 
  12.  // Try all delimiters and choose the delimiter which yields the shortest frame. 
  13.  int minFrameLength = Integer.MAX_VALUE; 
  14.  ByteBuf minDelim = null
  15.  // 其他分割符進行一次切分 
  16.  for (ByteBuf delim: delimiters) { 
  17.  int frameLength = indexOf(buffer, delim); 
  18.  if (frameLength >= 0 && frameLength < minFrameLength) { 
  19.  minFrameLength = frameLength
  20.  minDelim = delim
  21.  } 
  22.  } 
  23.  // 以下代碼省略 

根據它的名字可以知道,分隔符才是它的核心。它將分割符分成兩類,只有換行分割符(n或者rn)和其他。因此,需要注意的是,你可以定義多種分割符,它都是支持的。

3. LengthFieldBasedFrameDecoder

該類比較復雜,如果直接看方法容易把自己看混亂,因此我準備結合類上的解釋,先看看其私有變量。

2 bytes length field at offset 1 in the middle of 4 bytes header, strip the first header field and the length field, the length field represents the length of the whole message

Let's give another twist to the previous example. The only difference from the previous example is that the length field represents the length of the whole message instead of the message body, just like the third example. We have to count the length of HDR1 and Length into lengthAdjustment. Please note that we don't need to take the length of HDR2 into account because the length field already includes the whole header length.

  1. * BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) 
  2. * +------+--------+------+----------------+ +------+----------------+ 
  3. * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | 
  4. * | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" | 
  5. * +------+--------+------+----------------+ +------+----------------+ 
  • lengthFieldOffset :該字段代表 Length 字段是從第幾個字節開始的。上面的例子里,Length 字段是從第1個字節開始(HDR1 是第0個字節),因此該值即為0。
  • lengthFieldLength:該字段代表 Length 字段所占用的字節數。上面的例子里,Length 字段占用2個字節,因此該值為2。
  • lengthAdjustment:該字段代表 Length 字段結束位置到真正的內容開始位置的距離。上面例子里,因為 Length 字段的含義是整個消息(包括 HDR1、Length、HDR2、Actual Content,一般 Length 指的只是 Actual Content),所以 Length 末尾到真正的內容開始位置(HDR1的開始處),相當于減少3個字節,所以是-3。
  • initialBytesToStrip: 展示時需要從 Length 字段末尾開始跳過幾個字節。上面例子里,因為真正的內容是從 HDR1 開始的,最終展示的內容是從 HDR2 開始的,所以中間差了3個字節,所以該值是3。

該類的解碼方法比較復雜,有興趣的同學可以試著自己分析一下。

總結

 

 

這一篇主要是結合 Netty 里的源代碼講解了 Netty 中封裝成幀(Framing)的三種方式,相信你一定有了不一樣的理解。

 

責任編輯:趙寧寧 來源: 健程之道
相關推薦

2024-08-16 21:47:18

2019-10-24 07:35:13

TCP粘包Netty

2022-08-01 07:07:15

粘包半包封裝

2021-07-15 10:35:16

NettyTCPJava

2025-04-10 10:15:30

2020-10-15 18:31:36

理解Netty編解碼

2022-05-23 08:35:43

粘包半包數據

2024-06-03 08:09:46

2021-01-13 10:18:29

SocketNetty粘包

2024-12-19 11:00:00

TCP網絡通信粘包

2019-10-17 11:06:32

TCP粘包通信協議

2020-01-06 15:23:41

NettyTCP粘包

2019-11-12 15:15:30

網絡安全網絡安全技術周刊

2024-10-12 18:16:27

2020-03-10 08:27:24

TCP粘包網絡協議

2021-03-09 22:30:47

TCP拆包協議

2021-08-13 09:06:52

Go高性能優化

2022-04-28 08:38:09

TCP協議解碼器

2021-10-08 09:38:57

NettyChannelHand架構

2020-12-23 07:53:01

TCP通信Netty
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产在线一区二 | 99久久婷婷国产综合精品电影 | 欧美日韩国产精品一区二区 | 俺去俺来也www色官网cms | h在线 | 美女黄视频网站 | 99re在线视频精品 | 亚洲免费精品一区 | 麻豆久久久久 | 特级毛片爽www免费版 | 欧美国产亚洲一区二区 | 18gay男同69亚洲网站 | 亚洲区中文字幕 | 精品国产乱码久久久久久久久 | 亚洲女人天堂成人av在线 | 91原创视频 | 伊人网伊人网 | 国产成人在线视频播放 | 91精品国产综合久久久密闭 | 欧美日韩视频在线第一区 | 中文字幕综合在线 | 精品成人佐山爱一区二区 | 狠狠干综合视频 | 激情国产| 亚洲国产成人在线视频 | 精品一区二区三区四区 | 国产自产c区 | 一区二区三区免费网站 | 亚洲综合在线视频 | 欧美日韩在线观看视频网站 | 亚洲成人av一区二区 | 日韩精品一区二区三区在线观看 | www.亚洲精品 | 日本精品一区二区三区视频 | 91在线精品一区二区 | 中文字幕免费视频 | 久久成人av | 大陆一级毛片免费视频观看 | 欧美成人猛片aaaaaaa | 久久99精品久久久久久国产越南 | 成人欧美一区二区 |