tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况。

  • 1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包;
  • 2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包;
  • 3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为拆包;
  • 4.服务端分2次读取到了两个数据包,第一次读取到了部分D1,第二次读取D1剩余的部分和完整的D2包;
  • 5.如果此时服务端TCP接收滑动窗非常小,而数据包D1和D2都很大,很有可能发送第五种可能,即服务端多次才能把D1和D2接收完全,期间多次发生拆包情况。

由于底层的TCP无法理解上层的业务逻辑,所以在底层是无法确保数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:

  • 1.消息定长,例如每个报文的大小为固定长度200字节,如果不够,空位补空格;
  • 2.在包尾增加回车换行符进行分割;
  • 3.将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段,通常设计思路是消息头的第一个字段用int来表示消息的总长度;
  • 4.更复杂的应用层协议;

Netty对以上4种应用做了抽象,提供了4种解码器

LineBasedFrameDecoder:依次编译bytebuf中的可读字符,判断看是否有“\n”或者“\r\n”,如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持单行的最大长度。如果连续读取到最大长度后,仍然没有发现换行符,就会抛出异常,同时忽略掉之前读到的异常码流。

FixedLengthFrameDecoder:是固定长度解码器,它能按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包等问题。利用FixedLengthFrameDecoder解码,无论一次性接收到多少的数据,他都会按照构造函数中设置的长度进行解码;如果是半包消息,FixedLengthFrameDecoder会缓存半包消息并等待下一个包,到达后进行拼包,直到读取完整的包。

DelimiterBasedFrameDecoder:是自定义的分隔符解码,构造函数的第一个参数表示单个消息的最大长度,当达到该长度后仍然没有查到分隔符,就抛出TooLongFrameException异常,防止由于异常码流缺失分隔符导致的内存溢出。

LengthFieldBasedFrameDecoder:通过固定长度来区分整包消息。消息定长,报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。

netty的解码器与粘包和拆包的更多相关文章

  1. netty的解码器和粘包拆包

    Tcp是一个流的协议,一个完整的包可能会被Tcp拆成多个包进行发送,也可能把一个小的包封装成一个大的数据包发送,这就是所谓的粘包和拆包问题 粘包.拆包出现的原因: 在流传输中出现,UDP不会出现粘包, ...

  2. Netty学习(四)-TCP粘包和拆包

    我们都知道TCP是基于字节流的传输协议.那么数据在通信层传播其实就像河水一样并没有明显的分界线,而数据具体表示什么意思什么地方有句号什么地方有分号这个对于TCP底层来说并不清楚.应用层向TCP层发送用 ...

  3. netty 解决TCP粘包与拆包问题(一)

    1.什么是TCP粘包与拆包 首先TCP是一个"流"协议,犹如河中水一样连成一片,没有严格的分界线.当我们在发送数据的时候就会出现多发送与少发送问题,也就是TCP粘包与拆包.得不到我 ...

  4. 【Netty】TCP粘包和拆包

    一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...

  5. Netty入门系列(2) --使用Netty解决粘包和拆包问题

    前言 上一篇我们介绍了如果使用Netty来开发一个简单的服务端和客户端,接下来我们来讨论如何使用解码器来解决TCP的粘包和拆包问题 TCP为什么会粘包/拆包 我们知道,TCP是以一种流的方式来进行网络 ...

  6. Netty(4)Stream by codec(粘包与拆包)

    TCP/IP,传输的是byte[],将byte[]放入队列中.可能会发生粘包和拆包. 比如,客户端向服务端发送了2条消息,分别为D1,D2,可能产生的情况,如下图所示: 情况一:正常的. 情况二:粘包 ...

  7. Netty中粘包和拆包的解决方案

    粘包和拆包是TCP网络编程中不可避免的,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包和拆包 TCP是个“流”协议,所谓流,就是没有界限的一串 ...

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

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

  9. 粘包和拆包及Netty解决方案

    在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接.由于微服务往对方发送信息的时候,所有的请求都是使 ...

随机推荐

  1. Linux之查看文件大小和数目

    1.查看当前文件大小du -sh ./ du [-abcDhHklmsSx] [-L <符号连接>][-X <文件>][--block-size][--exclude=< ...

  2. Android ArryaList 笔记

    Arraylist相当于动态数组,可以动态的添加或者删除其中的元素. 参考链接 http://beginnersbook.com/2013/12/java-arraylist/ package com ...

  3. linux基础知识的总结

    例如以下内容是我对linux基础知识的总结,由于本人在初期学习linux的时候走了不少的弯路,对于基础的掌握耗费了不少的时间,所以为了后来者对linux的基础部分有个清晰的了解,特对基础知识进行了总结 ...

  4. shell脚本程序中循环、判断语句的介绍

    shell的循环主要有3种,for,while,until shell的分支判断主要有2种,if,case 一,for循环 C/C++ Code复制内容到剪贴板 #!/bin/bash for fil ...

  5. EasyTouch的使用官方文档操作步骤

    对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很 ...

  6. 查看当前mysql数据库实例中,支持的字符集有哪些,或者是否支持某个特定字符集

    需求描述: 查看当前mysql实例中支持哪些字符集,过滤特定的字符集 操作过程: 1.通过show character set来进行查看 mysql> show character set; + ...

  7. shell中判断一个变量是否为0或者为某个具体的值

    需求说明: 在实际写脚本的过程中,需要判断某个变量的值是否为某个数字, 比如,判断某个进程的数量是否为0用来确定进程是否存在,这样的情况. 简单来说,算术比较. 测试过程: 通过以下的脚本来判断mys ...

  8. Python图像处理库PIL的ImageSequence模块介绍

    ImageSequence模块包括了一个wrapper类,它能够让用户迭代訪问图形序列中每一帧图像. 一.ImageSequence模块的函数 1.  Iterator 定义:ImageSequenc ...

  9. Java类的设计----访问控制

    访问控制 可以对Java类中定义的属性和方法进行访问控制----规定不同的保护等级: public.protected.default.private //仅在类的内部可以访问. private St ...

  10. Mac下,如何把项目托管到Github上(Github Desktop的使用)

    在上一篇中,详细讲解了使用X-code和终端配合上传代码的方法,这种方法比较传统,中间会有坑,英文看起来也费劲,不过Github官方提供了一个Mac版的客户端,如下图: