参考文献:极客时间傅健老师的《Netty源码剖析与实战》Talk is cheap.show me the code!

什么是粘包和半包

  在客户端发送数据时,实际是把数据写入到了TCP发送缓存里面的。

  半包:顾名思义就是接收到半个包,如果发送的包的大小比TCP发送缓存的容量大,那么这个数据包就会被分成多个包,通过socket多次发送到服务端,服务端第一次从接受缓存里面获取的数据,实际是整个包的一部分,半包不是说只收到了全包的一半,是说收到了全包的一部分。

   粘包:如果发送的包的大小比TCP发送缓存容量小,并且TCP缓存可以存放多个包,那么客户端和服务端的一次通信就可能传递了多个包,这时候服务端从接受缓存就可能一下读取了多个包

举个栗子:

  我们现在发送两条消息:“ABC”,“DEF”,那么对方接收到的消息不一定是这种格式的,对方可能一次性就接收到“ABCDEF”,也可能分好几次接收到“AB”,“CD”,“EF”,或者更为恶劣一次接收到了两个消息“A”,“BCDEF”。那么这样一次接收两个消息的称为粘包现象,分三次四接收到多个不完整的现象是半包现象。

粘包的主要原因:

  发送方每次写入数据  < 套接字缓冲区大小,接收方读取套接字缓冲区数据不够及时。

半包的主要原因:

   发送方写入数据 > 套接字缓冲区大小,还有就是发送的数据大于协议的MTU(Maximum Transmission Unit 最大传输单元)的时候必须拆包。(MTU其实就是TCP协议每层的大小)

换个角度:

  收发:一个发送可能被多次接收,多次发送可能被一次接收

  传输:一个发送可能占用多个传输包,多个发送可能公用一个传输包

根本原因:

  TCP是流动协议,消息无边界。(UDP像邮寄的包裹,虽然一次运输多个的,但每个包裹都有“界限”,一个一个签收,所以无粘包、半包问题)

解决问题的根本手段:找出消息的边界

  

Netty对三种常用封帧方式的支持(三个类都继承ByteTomessageDecoder.java)

解读Netty处理粘包、半包的源码-------解码核心工作流程:

  先找到ByteToMessageDecoder.java,可以看到它继承了ChannelInboundHandlerAdapter.java

 这个ChannelInboundHandlerAdapter有个核心的入口方法“channelRead()”;

图中的msg就相当于我们的数据,开始就把数据转换成data,

ByteBuf data = (ByteBuf) msg;

然后判断cumulation是否为null,cumulation是数据积累器,用来积累数据。

ByteBuf cumulation;
first = cumulation == null;
if (first) {
cumulation = data;
} else {
cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
}

第一次的时候肯定为null  所以first是true,直接把data数据给了cumulation。再接下来就是解码:

 callDecode(ctx, cumulation, out);

进入具体方法

参数中的in就是数据积累器中的数据,也就是我们传入的数据。往下走又这么个方法调用:

decodeRemovalReentryProtection(ctx, in, out);

需要注意的是:decode中时,不能执行完handler remove清理操作,decode完之后需要清理数据,改方法的名称长久是标识功能的。点进去可以查看

可以看出有个decodeState = STATE_CALLING_CHILD_DECODE;这个就是处理刚才remove handler 的;接下来就是“decode(ctx, in, out);”;这个decode是个抽象方法

之前说过Netty对三种封帧的支持分别是:“FixedLengthFrameDecoder”,“DelimiterBasedFrameDecoder”,“LengthFieldBasedFrameDecoder”。这里以“FixedLengthFrameDecoder”为例,所以点开FixedLengthFrameDecoder的decode();

   @Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}

然后再进去查看Object decoded = decode(ctx, in);

protected Object decode(
@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {
return null;
} else {
return in.readRetainedSlice(frameLength);
}
}

这时候就能发现关键点,代码标粗,这个in还是数据积累器的数据,取得之后进行判断,如果小于则返回null不能解出,否则解出。这样一来就完成了一个数据解析的过程。

我只想做的更好,仅此而已

TCP的粘包、半包和Netty的处理的更多相关文章

  1. Netty 粘包/半包原理与拆包实战

    Java NIO 粘包 拆包 (实战) - 史上最全解读 - 疯狂创客圈 - 博客园 https://www.cnblogs.com/crazymakercircle/p/9941658.html 本 ...

  2. netty解决粘包半包问题

    前言:开发者用到TCP/IP交互时,偶尔会遇到粘包或者半包的数据,这种情况有时会对我们的程序造成严重的影响,netty框架为解决这种问题提供了若干框架 1. LineBasedFrameDecoder ...

  3. Http 调用netty 服务,服务调用客户端,伪同步响应.ProtoBuf 解决粘包,半包问题.

    实际情况是: 公司需要开发一个接口给新产品使用,需求如下 1.有一款硬件设备,客户用usb接上电脑就可以,但是此设备功能比较单一,所以开发一个服务器程序,辅助此设备业务功能 2.解决方案,使用Sock ...

  4. socket编程 TCP 粘包和半包 的问题及解决办法

    一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...

  5. Netty - 粘包和半包(上)

    在网络传输中,粘包和半包应该是最常出现的问题,作为 Java 中最常使用的 NIO 网络框架 Netty,它又是如何解决的呢?今天就让我们来看看. 定义 TCP 传输中,客户端发送数据,实际是把数据写 ...

  6. Netty—TCP的粘包和拆包问题

    一.前言 虽然TCP协议是可靠性传输协议,但是对于TCP长连接而言,对于消息发送仍然可能会发生粘贴的情形.主要是因为TCP是一种二进制流的传输协议,它会根据TCP缓冲对包进行划分.有可能将一个大数据包 ...

  7. 关于TCP封包、粘包、半包

    关于Tcp封包 很多朋友已经对此作了不少研究,也花费不少心血编写了实现代码和blog文档.当然也充斥着一些各式的评论,自己看了一下,总结一些心得. 首先我们学习一下这些朋友的心得,他们是: http: ...

  8. Netty - 粘包和半包(下)

    上一篇介绍了粘包和半包及其通用的解决方案,今天重点来看一下 Netty 是如何实现封装成帧(Framing)方案的. 解码核心流程 之前介绍过三种解码器FixedLengthFrameDecoder. ...

  9. TCP的组包、半包、粘包与分包

    一.概念 1)组包.简单的说就是tcp协议把过大的数据包分成了几个小的包传输,接收方要把同一组的数据包重新组合成一个完整的数据包. 2)半包.指接受方没有接受到一个完整的包,只接受了部分,这种情况主要 ...

随机推荐

  1. Git 提交代码和更新代码

    首先,操作之前一定要看清分支!! 其次,提交代码之前一定要先更新代码!! git branch        -----查看当前分支 git pull             -----更新代码到本地 ...

  2. Python3 Address already in use 解决方法

    1.查看使用端口号netstat -ntlp 2.根据端口号找到pid 3.杀死程序 kill -9 pid 4.重新启动程序 简单粗暴 我使用python3时编写Socket,linux系统下使用c ...

  3. BZOJ 2402 陶陶的难题II (树链剖分、线段树、凸包、分数规划)

    毒瘤,毒瘤,毒瘤-- \(30000\)这个数据范围,看上去就是要搞事的啊... 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2402 ...

  4. HTTP之缓存技术

    1. 缓存简介 缓存是位于服务器和客户端的中间单元,主要根据用户代理发送过来的请求,向服务器请求相关内容后提供给用户,并保存内容副本,例如 HTML 页面.图片.文本文件或者流媒体文件.然后,当下一个 ...

  5. IDEA Method definition shorthands are not supported by current JavaScript version

    sentinel-dashboard前端用到了AngularJS v1.4.8,在IDEA里修改js,触发js验证时有一些js文件会出现红色波浪线. 在代码行里鼠标一上去提示信息:Method def ...

  6. 基于eclipse的java与mysql开发环境的搭建

    本文主要介绍  Java与MySQL的连接 1.安装jdk 略~ 园子里有很多 2.安装mysql 略~ 3.下载并安装JDBC,通过mysql官网下载  http://dev.mysql.com/d ...

  7. 指定pip清华源

    临时指定: pip install cefpython3 -i https://pypi.tuna.tsinghua.edu.cn/simple 一直使用:pip的配置文件为%HOME%/pip/pi ...

  8. 如何使用git send-email发送补丁?

    答: git send-email <patch-name> --to <username>@<example>.com --cc <username> ...

  9. 真正解决方案:phpMyAdmin #1089 - Incorrect prefix key; the storage engine doesn't support unique prefix key

    先直接给解决方案: 点击A_I后,不要输入大小,直接点击执行!!! 分析 当你在使用phpMyAdmin 创建数据库表的时候,一般我们需要设置一个主键,然后让其自增长,但是有时候当你设置完成后,你可能 ...

  10. 微信小程序跳转问题:wx.redirectTo、wx.navigateTo、wx.reLaunch、wx.switchTap、wx.navigateBack区别

    wx.redirectTo:关闭当前页,跳转到指定页: wx.navigateTo:保留当前页,跳转到指定页: wx.reLaunch:关闭所有页面,打开到应用内的某个页面. wx.switchTap ...