成人免费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

粘包半包封裝

2025-04-10 10:15:30

2021-07-15 10:35:16

NettyTCPJava

2020-10-15 18:31:36

理解Netty編解碼

2022-05-23 08:35:43

粘包半包數據

2024-12-19 11:00:00

TCP網絡通信粘包

2024-06-03 08:09:46

2021-01-13 10:18:29

SocketNetty粘包

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技術棧公眾號

主站蜘蛛池模板: 妖精视频一区二区三区 | www.天天操 | 欧美视频一级 | 久久久久国产成人精品亚洲午夜 | 精品二区| 国产高清精品一区二区三区 | 视频第一区 | 黄色小视频入口 | 欧美专区日韩 | 精品在线一区 | av在线播放国产 | 欧美日韩看片 | 天天看天天干 | 久久一区二区免费视频 | 欧美一级免费片 | 亚洲一区二区av | 国产乱码一二三区精品 | 精品成人在线视频 | 成年免费大片黄在线观看岛国 | 狠狠婷婷综合久久久久久妖精 | 久久在线看| 黄色在线播放视频 | 91久久久久久久久久久久久 | 免费国产一区 | 免费午夜视频在线观看 | 黑人一级片视频 | 人人亚洲 | 久久国产视频一区 | 免费在线日韩 | 粉嫩av久久一区二区三区 | 欧美一区二区小视频 | 毛片网在线观看 | 午夜在线| 99pao成人国产永久免费视频 | 日韩成人| 亚洲欧美日韩一区二区 | 国产成人精品一区二区 | 黄免费观看 | www.色.com | 欧美极品在线视频 | 午夜精品一区 |