粘包出现的原因:服务端与客户端没有约定好要使用的数据结构。Socket Client实际是将数据包发送到一个缓存buffer中,通过buffer刷到数据链路层。因服务端接收数据包时,不能断定数据包1何时结束,就有可能出现数据包2的部分数据结合数据包1发送出去,导致服务器读取数据包1时包含了数据包2的数据。这种现象称为粘包。
分包:数据包数据被分开一部分发送出去,服务端一次读取数据时可能读取到完整数据包的一部分,剩余部分被第二次读取。

解决办法一般是通过定义一个稳定的结构,比如一个完整的消息包数据结构为:包头+数据包长度+数据包。

服务器有的通过重写FrameDecoder的decode方法来处理粘包与分包;代码示例如下:

public class MyDecoder extends FrameDecoder {@Overrideprotected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {if(buffer.readableBytes() > 4){if(buffer.readableBytes() > 2048){buffer.skipBytes(buffer.readableBytes());}//标记buffer.markReaderIndex();//长度int length = buffer.readInt();if(buffer.readableBytes() < length){buffer.resetReaderIndex();//缓存当前剩余的buffer数据,等待剩下数据包到来return null;}//读数据byte[] bytes = new byte[length];buffer.readBytes(bytes);//往下传递对象return new String(bytes);}//缓存当前剩余的buffer数据,等待剩下数据包到来return null;}}

然后再设置管道属性的时候,添加如下代码即可。

大家难免会有疑惑,decode处理的数据如何传递给下一个处理类;另外,decode处理类返回null之后会怎么样。我们通过这样一个场景(第一次来的包数量不够,不足以解析,第二次才能解析)来分析源码。当然了,这种情况支持,没有粘包和分包的正常情况也是支持的。

下面我们一起看下FrameDecoder的源码,,通过上一篇文章大家可以知道,既然这个类继承于SimpleChannelUpstreamHandler,那么消息来了之后首先会调用他的messageReceived方法,源码如下:

当第一次进来之后,由于cumulation是空的,所以会直接调用callDecode方法

通过这段代码,我们可以知道,首先会判断cumulation,也就是上面方法传入的input里面是不是有数据可以读取,如果有的话会先记录原始的读取位置,然后调用我们重写的decoder,如果返回的是null,并且现在的读取位置和原始的一致,那么认为没有办法完成读取,所以直接break跳出循环,然后返回到调用方之后,直接执行finally方法。

该方法是将数据更新到cumulation中。

待下次再来处理数据的时候,由于cumulation中已经有了数据,会进行追加,然后调用callDecode方法,此时会执行如下方法

查看该方法源码:

发现会调用fireMessageReceived方法,该方法源码如下:

至此,通过上一篇文章我们知道,这个方法是循环取出handler执行,所以也就明白了Decoder的decode为什么能把消息传递给别的处理类了。

除此之外,上面的callDecode里面是个while循环,也就是说如果里面有多个消息包,也是可以处理的。

Netty学习09-粘包和分包及FrameDecoder源码解析相关推荐

  1. 【深度学习实战03】——YOLO tensorflow运行及源码解析

    本文章是深度学习实战系列第三讲文章,以运行代码+源码分析 为主: 转载请注明引用自:https://blog.csdn.net/c20081052/article/details/80260726 首 ...

  2. 深度学习大模型训练--分布式 deepspeed PipeLine Parallelism 源码解析

    deepspeed PipeLine Parallelism 源码解析 basic concept PipeDream abstract 1F1B 4 steps Code comprehension ...

  3. Java并发包源码学习系列:LBD双端阻塞队列源码解析

    尝试将节点加入到first之前,更新first,如果插入之后超出容量,返回false. private boolean linkFirst(Node node) { // assert lock.is ...

  4. [源码解析] 深度学习流水线并行 PipeDream(3)--- 转换模型

    [源码解析] 深度学习流水线并行 PipeDream(3)- 转换模型 文章目录 [源码解析] 深度学习流水线并行 PipeDream(3)--- 转换模型 0x00 摘要 0x01 前言 1.1 改 ...

  5. [源码解析] 深度学习分布式训练框架 horovod (10) --- run on spark

    [源码解析] 深度学习分布式训练框架 horovod (10) - run on spark 文章目录 [源码解析] 深度学习分布式训练框架 horovod (10) --- run on spark ...

  6. [源码解析] 深度学习流水线并行 PipeDream(6)--- 1F1B策略

    [源码解析] 深度学习流水线并行 PipeDream(6)- 1F1B策略 文章目录 [源码解析] 深度学习流水线并行 PipeDream(6)--- 1F1B策略 0x00 摘要 0x01 流水线比 ...

  7. [源码解析] 深度学习分布式训练框架 horovod (11) --- on spark --- GLOO 方案

    [源码解析] 深度学习分布式训练框架 horovod (11) - on spark - GLOO 方案 文章目录 [源码解析] 深度学习分布式训练框架 horovod (11) --- on spa ...

  8. Netty解决TCP的粘包和分包(二)

    2019独角兽企业重金招聘Python工程师标准>>> Netty解决TCP的粘包和分包(二) 使用LengthFieldBasedFrameDecoder解码器分包 先看一下这个类 ...

  9. 什么是粘包和拆包,Netty如何解决粘包拆包?

    Netty粘包拆包 TCP 粘包拆包是指发送方发送的若干包数据到接收方接收时粘成一包或某个数据包被拆开接收. 如下图所示,client 发送了两个数据包 D1 和 D2,但是 server 端可能会收 ...

最新文章

  1. Google的Java开发规范
  2. svn 主干(trunk)、分支(branch )、标记(tag) 简介
  3. 发布至今18年,为什么SQLite一定要用C语言来开发?
  4. 线段树教做人系列(3) HDU 4913
  5. html5判断设备的动作
  6. 产品经理需要掌握的9种共性推荐策略
  7. JAVA字符串怎么转换成整数
  8. 练习四十八:面向对象执行效率
  9. 传输表空间--使用Rman方式
  10. VS2017+海康威视工业相机调用查找不到设备的问题
  11. 性能监视器 Performance Monitor-对SQLSERVER进行性能监控
  12. 编译原理-第一章:引论
  13. 国内外优秀的计算机视觉团队汇总
  14. UiPath Excel内容去重操作
  15. 强制域名使用 HTTPS(SSL)
  16. 隐藏滚动条css3实现滚动同时隐藏滚动条
  17. 北邮自考计算机专业好过吗,有参加过北京邮电大学自考答辩的吗,难吗
  18. python金融编程入门_【量化小讲堂- Python、pandas技巧系列】如何快速上手使用Python进行金融数据分析...
  19. 在IOS上YUV NV21格式的CVPixelBufferRef转opencv的RGB格式cv::Mat的方法
  20. 创业公司的技术团队文化

热门文章

  1. 学海领航c语言答案,学海领航语文单元测试卷答案.doc
  2. A2DP link key request 格式 说明
  3. 逻辑越权漏洞-水平垂直越权
  4. 初学区块链DAPP开发的一些总结
  5. 黑莓使用必看帖子大汇集(转载)
  6. 解决内存泄漏更加清楚的认识到Java匿名类与外部类的关系
  7. 富斯遥控器/接收机的PWM/PPM/iBUS/SBUS通道设置
  8. 27m3氨基酸发酵反应釜设计
  9. Gurobi安装详细指南-2020最新版
  10. hp刀片服务器装系统,hp刀片服务器安装系统教程精选.docx