Netty笔记9:粘包半包
Netty笔记1:线程模型
Netty笔记2:零拷贝
Netty笔记3:NIO编程
Netty笔记4:Epoll
Netty笔记5:Netty开发实例
Netty笔记6:Netty组件
Netty笔记7:ChannelPromise通知处理
Netty笔记8:ByteBuf使用介绍
Netty笔记9:粘包半包
Netty笔记10:LengthFieldBasedFrameDecoder
Netty笔记11:编解码器
Netty笔记12:模拟Web服务器
Netty笔记13:序列化
文章目录
- 前言
- 什么是粘包/半包
- 那如何解决粘包,半包?
前言
粘包/半包是一个很重要的概念,在网络数据传输中一定存在的问题,我们需要理解和会解决,以及运用Netty提供的工具解决。
什么是粘包/半包
粘包:在客户端和服务端之间,会维持一个连接,可以发送多个数据包,但是如果发送的网络数据包太小,那么它会启用Nagle算法,对较小的数据包进行合并,待超时或者数据包大小够大时再发送,也是因为这个原因,TCP的网络延迟会比UDP高一些,服务端对于这样合并发送的消息就无法区分哪些数据是分开发送的,也就是粘包;服务器再接收到数据后,放到缓冲区中,如果消息没有被及时从缓冲区取走,下次再取数据的时候可能会一次取出多个数据包的情况,产生粘包现象;
之前提到UDP,它本身作为无连接的不可靠传输协议,适合频繁发送数据较小的数据包,它不会对数据包进行合并发送,也就是发送什么,就接收到什么。
拆包:服务器将粘粘在一起的数据包进行拆分;
半包/分包:网络传输的套接字的发送缓冲区不够,或者达到了TCP最大报文长度(MSS)大小,导致接收到的数据不完整,还需要接收剩余的数据;
下面模拟粘包场景
修改client的handler,尝试在客户端建立连接时发送100个数据包给服务端
@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {// 连接成功后激活这个方法for (int i = 0; i < 100; i++) {// 这里消息,再次用分隔符进行分割保证100个数据都是独立的数据包ctx.writeAndFlush(Unpooled.copiedBuffer(("我已经连上了"+System.getProperty("line.separator")).getBytes(CharsetUtil.UTF_8)));}}
之后在服务端接收数据,并统计接收次数
public class ServerHandler extends ChannelInboundHandlerAdapter {static int count = 0;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buffer = (ByteBuf)msg;System.out.println("接收到数据:" + buffer.toString(CharsetUtil.UTF_8));System.out.println("记录次数:" + ++count);System.out.println("ok--------------------------------");super.channelRead(ctx, msg);}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {super.channelActive(ctx);}
}
结果如下,服务端对100个的接收,其实只是读取了一次,甚至于我们增加了分隔符,也还是把这100个数据包,合并成一个发送了过来

TCP最大数据长度就等于65535-20(20是固定的IP头部)=65495,一个http能发送的最大报文长度受诸多影响,如MSS,网络环境,应用层协议等,所以,理论上是小于65495这个值的。
会出现粘包,半包,是 由TCP传输层协议决定的,因为TCP不知道传输的数据多少字节是一个包,所以,这个现象是由应用层解决的。
那如何解决粘包,半包?
方法一:TCP不知道多少字节算一个包,所以我们可以添加分隔符,而这个分隔符是需要双端都要统一的,不然一端以回车换行为分隔符,另一端以空格为分隔符,就会造成数据分包不对;
方法二:指定数据长度,需要双端统一,需要在传输的字节中,添加数据包长度,在另一端读取解码时就可以知道读取多少为一个数据包;
方法一示例:
那我们定义一个回车换行符为分隔符,并添加到channelInitializer中;
注意:我这里以System.getProperty("line.separator")为分隔符,这个变量取自计算机操作系统,win和linux他们的值不同,所以,需要明确这个值,我这里是偷懒了。
如果说是回车换行为分隔符的解码器,Netty已经提供了一个LineBasedFrameDecoder;
ByteBuf byteBuf = Unpooled.wrappedBuffer(System.getProperty("line.separator").getBytes(StandardCharsets.UTF_8));socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, byteBuf));

来看结果:

方法二示例:
指定数据长度在数据包中,并解码,这个在Netty中是有实现的:
LengthFieldPrepender:经过这个过滤器会在发送的消息前增加一个长度字段,一般使用只有一个参数的构造器,指定长度的大小,这个长度不会改变整个消息的长度;如果要将长度累计到消息长度上,使用new LengthFieldPrepender(4,true)
一般是配合LengthFieldBasedFrameDecoder使用。
例如:
bootstrap.group(group, work)// server指定为ServerChannel.channel(NioServerSocketChannel.class)// 绑定端口.localAddress(8080)// 事件处理器.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline()// 数据写出时,增加一个4字节长度的字段.addLast(new LengthFieldPrepender(4)).addLast(new LengthFieldBasedFrameDecoder(65535, 0, 4, 0, 4));
关于LengthFieldBasedFrameDecoder的详细说明,在下一篇。
相关文章:
Netty笔记9:粘包半包
Netty笔记1:线程模型 Netty笔记2:零拷贝 Netty笔记3:NIO编程 Netty笔记4:Epoll Netty笔记5:Netty开发实例 Netty笔记6:Netty组件 Netty笔记7:ChannelPromise通知处理 Netty笔记8…...
【算法方法总结·三】滑动窗口的一些技巧和注意事项
【算法方法总结三】滑动窗口的一些技巧和注意事项 【算法方法总结一】二分法的一些技巧和注意事项【算法方法总结二】双指针的一些技巧和注意事项【算法方法总结三】滑动窗口的一些技巧和注意事项 【滑动窗口】 数组的和 随着 右边指针 移动一定是 非递减 的,就是 …...
LabVIEW虚拟弗兰克赫兹实验仪
随着信息技术的飞速发展,虚拟仿真技术已经成为教学和研究中不可或缺的工具。开发了一种基于LabVIEW平台开发的虚拟弗兰克赫兹实验仪,该系统不仅能模拟实验操作,还能实时绘制数据图形,极大地丰富了物理实验的教学内容和方式。 …...
spring boot + vue 搭建环境
参考文档:https://blog.csdn.net/weixin_44215249/article/details/117376417?fromshareblogdetail&sharetypeblogdetail&sharerId117376417&sharereferPC&sharesourceqxpapt&sharefromfrom_link. spring boot vue 搭建环境 一、浏览器二、jd…...
清华团队提出HistoCell,从组织学图像推断超分辨率细胞空间分布助力癌症研究|顶刊精析·25-03-02
小罗碎碎念 今天和大家分享一篇2025-02-21发表于nature communications的文章,内容涉及病理空转单细胞。 从组织学图像推断细胞空间分布对癌症研究意义重大,但现有方法存在标注工作量大、分辨率或特征挖掘不足等局限。研究旨在开发一种高效准确的方法。 …...
分布式锁—2.Redisson的可重入锁一
大纲 1.Redisson可重入锁RedissonLock概述 2.可重入锁源码之创建RedissonClient实例 3.可重入锁源码之lua脚本加锁逻辑 4.可重入锁源码之WatchDog维持加锁逻辑 5.可重入锁源码之可重入加锁逻辑 6.可重入锁源码之锁的互斥阻塞逻辑 7.可重入锁源码之释放锁逻辑 8.可重入锁…...
html+js 轮播图
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>轮播图示例</title><style>/* 基本样式…...
vue3:初学 vue-router 路由配置
承上一篇:nodejs:express js-mdict 作为后端,vue 3 vite 作为前端,在线查询英汉词典 安装 cnpm install vue-router -S 现在讲一讲 vue3:vue-router 路由配置 cd \js\mydict-web\src mkdir router cd router 我还…...
23种设计模式之《备忘录模式(Memento)》在c#中的应用及理解
程序设计中的主要设计模式通常分为三大类,共23种: 1. 创建型模式(Creational Patterns) 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。 工厂方法模式࿰…...
Python 爬取唐诗宋词三百首
你可以使用 requests 和 BeautifulSoup 来爬取《唐诗三百首》和《宋词三百首》的数据。以下是一个基本的 Python 爬虫示例,它从 中华诗词网 或类似的网站获取数据并保存为 JSON 文件。 import requests from bs4 import BeautifulSoup import json import time# 爬取…...
C语言408考研先行课第一课:数据类型
由于408要考数据结构……会有算法题…… 所以,需要C语言来进行一个预备…… 因为大一贪玩,C语言根本没学进去……谁能想到考研还用得到呢?【手动doge(bushi) 软件用的是Clion,可以自行搜索教程下载使用。…...
03 HarmonyOS Next仪表盘案例详解(二):进阶篇
温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! 文章目录 前言1. 响应式设计1.1 屏幕适配1.2 弹性布局 2. 数据展示与交互2.1 数据卡片渲染2.2 图表区域 3. 事件处理机制3.1 点击事件处理3.2 手势…...
探秘基带算法:从原理到5G时代的通信变革【四】Polar 编解码(一)
文章目录 2.3 Polar 编解码2.3.1 Polar 码简介与发展背景2.3.2 信道极化理论基础对称容量与巴氏参数对称容量 I ( W ) I(W) I(W)巴氏参数 Z ( W ) Z(W) Z(W)常见信道信道联合信道分裂信道极化 本博客为系列博客,主要讲解各基带算法的原理与应用,包括&…...
基础篇(一)强化学习是什么?从零开始理解智能体的学习过程
强化学习是什么?从零开始理解智能体的学习过程 你是否曾好奇过,人工智能是如何在复杂的环境中学会做出决策的?无论是打游戏的AI,还是自动驾驶的汽车,还是最近很火的DeepSeek它们的背后都离不开一种强大的技术——强化…...
如何直接导出某个conda环境中的包, 然后直接用 pip install -r requirements.txt 在新环境中安装
1. 导出 Conda 环境配置 conda list --export > conda_requirements.txt这将生成一个 conda_requirements.txt 文件,其中包含当前环境中所有包的列表及其版本信息。 2. 转换为 requirements.txt 文件 grep -v "^#" conda_requirements.txt | cut -d …...
基于 HTML、CSS 和 JavaScript 的智能九宫格图片分割系统
目录 1 前言 2 技术实现 2.1 HTML 结构 2.2 CSS 样式 2.3 JavaScript 交互 3 代码解析 3.1 HTML 部分 3.2 CSS 部分 3.3 JavaScript 部分 4 完整代码 5 运行结果 6 总结 6.1 系统特点 6.2 使用方法 1 前言 在当今数字化的时代,图片处理需求日益增长。…...
委托者模式(掌握设计模式的核心之一)
目录 问题: 举例: 总结:核心就是利用Java中的多态来完成注入。 问题: 今天刷面经,刷到装饰者模式,又进阶的发现委托者模式,发现还是不理解,特此记录。 举例: 老板…...
MySQL-高级查询
查询处理 排序(默认不是按主键排序的) order by 字段1[,字段2] [asc|desc] 默认是升序排序也可以指定 select 列表中列的序号进行排序如果是多个字段,那么在上一个字段排序完的基础上排序下一个 限制数量 limit 行数࿰…...
R JSON 文件
R JSON 文件 引言 在当今的数据分析和处理领域,R语言作为一种功能强大的统计计算和图形展示工具,被广泛应用于各种数据分析任务中。随着大数据时代的到来,数据的格式和结构变得越来越多样化。JSON(JavaScript Object Notation&a…...
Apache Kafka单节点极速部署指南:10分钟搭建开发单节点环境
Apache Kafka单节点极速部署指南:10分钟搭建开发单节点环境 Kafka简介: Apache Kafka是由LinkedIn开发并捐赠给Apache基金会的分布式流处理平台,现已成为实时数据管道和流应用领域的行业标准。它基于高吞吐、低延迟的设计理念,能够…...
Redis7——进阶篇(一)
前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 基础篇: Redis(一)Redis(二)Redis(三)Redis&#x…...
点云配准技术的演进与前沿探索:从传统算法到深度学习融合(4)
4、点云配准面临的挑战与应对策略 4.1 点云配准面临的主要挑战 在点云配准的实际应用中,尽管已经取得了显著的研究成果,但仍然面临着诸多复杂而严峻的挑战,这些挑战严重制约了点云配准技术在更多领域的广泛应用和深入发展。 在自动驾驶场景…...
Linux·数据库INSERT优化
在业务中,我们经常会要对数据进行存储,对于少量数据插入时,我们可以直接使用 INSERT 插入数据,但是当我们需要插入的数据比较多时,使用 INSERT 插入的话时间消耗是很大的,具体而言单次插入600时,…...
Sourcetrail 代码分析工具
Sourcetrail 概述 Sourcetrail 是一个代码分析工具,它旨在帮助开发人员理解和导航复杂的代码库。它可以创建代码库的可视化图形,显示代码中的类、函数、变量、依赖关系等信息,从而帮助开发人员更好地理解代码结构和关系,降低维护…...
从数据到决策,永洪科技助力良信电器“智”领未来
在数字经济浪潮汹涌的时代,数字化转型已成为企业增强竞争力、实现可持续发展的必由之路。良信电器,作为国内知名的电气设备制造企业,积极响应时代号召,携手永洪科技,共同开启了数字化转型的新篇章。 上海良信电器股份有…...
Python-04BeautifulSoup网络爬虫
2025-03-04-BeautifulSoup网络爬虫 记录BeautifulSoup网络爬虫的核心知识点 文章目录 2025-03-04-BeautifulSoup网络爬虫 [toc]1-参考网址2-学习要点3-核心知识点1. 安装2. 导入必要的库3. 发送 HTTP 请求4. 创建 BeautifulSoup 对象5. 解析 HTML 内容5.1 查找标签5.2 根据属性…...
Spring框架自带的定时任务:Spring Task详解
文章目录 一、基本使用1、配置:EnableScheduling2、触发器:Scheduled 二、拓展1、修改默认的线程池2、springboot配置 三、源码分析参考资料 一、基本使用 1、配置:EnableScheduling import org.springframework.context.annotation.Config…...
深入探索像ChatGPT这样的大语言模型
参考 【必看珍藏】2月6日,安德烈卡帕西最新AI普及课:深入探索像ChatGPT这样的大语言模型|Andrej Karpathy fineweb知乎翻译介绍 fineweb-v1原始连接 fineweb中文翻译版本 Chinese Fineweb Edu数据集 查看网络的内部结果,可以参…...
week 3 - More on Collections - Lecture 3
一、Motivation 1. Java支持哪种类型的一维数据结构? Java中用于在单一维度中存储数据的数据结构,如arrays or ArrayLists. 2. 如何在Java下创建一维数据结构?(1-dimensional data structure) 定义和初始化这些一…...
机器学习11-经典网络解析
机器学习11-经典网络解析 AlexNetImageNet 大规模视觉识别挑战赛一、赛事背景与目的二、数据集与任务设置三、参赛规则与流程四、评审标准与机制五、历史与影响六、中国团队的表现 贡献解析CONV1层MaxP00L1层NORM1层CONV2层 CONV3、CONV4层CONV4,Max POOL3 层FC6、F…...
