Netty处理TCP粘包、拆包问题之DelimiterBasedFrameDecoder

unity打包流程整理-Windows/Mac/Linux平台 1.Platform(平台)功能: 选择目标构建的目标平台选项PC, Mac & Linux Standalone: 适用于 Windows、Mac 和 Linux 平台2.Target Platform(目标平台)功能: 选择具体的操作系统版本选项Windows: 针对 Windows 操作系统Mac: 针对 macOS 操作系统Linux: 针对 Linux 操作系统3.Architecture(架构)功能: 选择应用程序的目标处理器架构选项x86: 针对 32 位系统。 阅读详情

熟悉TCP编程的可能都知道,无论是服务器还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP低层的粘包/拆包机制。

TCP一个“流”协议,所谓流就是没有界限的传送数据。大家可以想象一下,如果河里的水就好比数据,他们是连成一片的,没有分界线,TCP低层并不了解上层的业务数据具体的含义,它会根据TCP缓冲区的实际情况进行包的划分,就是说,在业务上,我么一个完成的包可能会被TCP分成多个包进行发送,也可能把多个小包封装成一个大的数据包发送出去,这就是所谓的TCP尿包、拆包问题。

稍微分析一下TCP粘包、拆包问题的产生原因:

    1、应用程序write写入的字节大小大于套接口发送缓冲区的大小

    2、进行MSS大小的TCP分段

    3、以太网帧的payload大于MTU进行IP分片。

粘包拆包问题的解决方法,根据业界主流协议的有三种方案:

    1、消息定长,例如每个报文的大小固定为200个字节,如果不够,空位补空格。

    2、在包尾部增加特殊字符进行分割,例如加回车等

    3、将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后进行业务逻辑的处理。

 

Netty对以上3种应用做了抽象,提供了4种解码器,有了解码器,码农们不用考虑TCP的粘包、拆包的问题了。

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

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

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

 

下面的例子是自定义的分隔符解码器。

服务端Server:

public class Server {
	public static void main(String[] args) throws Exception {
		//1、第一个线程组 是用于处理服务器接收客户端连接的
		EventLoopGroup bossGroup  = new NioEventLoopGroup();
		//2、第二个线程组 是用于进行网络通信的(网络读写的)
		EventLoopGroup workGroup = new NioEventLoopGroup();
		//3、创建一个辅助工具类Bootstrap,用于服务通道的一系列配置
		ServerBootstrap sb = new ServerBootstrap();
		sb.group(bossGroup, workGroup)              //绑定两个线程组
		.channel(NioServerSocketChannel.class)      //指定NIO的模式
		.option(ChannelOption.SO_BACKLOG, 1014)     //设置tcp缓冲区大小
		.option(ChannelOption.SO_SNDBUF, 32*2014)   //设置发送缓冲区大小
		.option(ChannelOption.SO_RCVBUF,32*2014)    //设置接受缓冲区大小
		.option(ChannelOption.SO_KEEPALIVE, true)   //保持连接
		.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel sc) throws Exception {
				//为了解决拆包粘包的问题,我们可以设置特殊的分隔符
				ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
				//第一个参数表示单个消息的最大长度  第二个参数就是特殊分隔符  (当消息到了最大长度还没查到分隔符,那么就会报错TooLongFrameException异常)
				sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
				//设置字符串形式的编码
				sc.pipeline().addLast(new StringEncoder());
				//设置字符串形式的解码,以后在Handler那里获取的msg就是String类型的了。
				sc.pipeline().addLast(new StringDecoder());
				sc.pipeline().addLast(new ServerHandler()); //配置具体数据接收方法的处理器
			}
		});
		
		
		//4、绑定服务端指定的端口,进行监听
		ChannelFuture f = sb.bind(8765);
		
		//Thread.sleep(1000000);
		//5、等待关闭
		f.channel().closeFuture().sync();
		
		bossGroup.shutdownGracefully();
		workGroup.shutdownGracefully();
	}
}

服务器事件处理器ServerHandler:

public class ServerHandler extends ChannelHandlerAdapter{

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		//因为配置了字符串形式的解码,所以msg会是String类型
		String data = (String)msg;
		System.out.println("Server接收到的数据:"+data);
		//服务器给客户端返回数据 注意,返回的字符串最后一定得加上设置的分隔符$_
		String str = "客户端你好$_";
		ctx.writeAndFlush(str); //直接调用writeAndFuls方法就直接写完就flush
		
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

客户端Client:

public class Client {
	public static void main(String[] args) throws Exception {
		//1、创建线程组,客户端和服务端不一样,客户端只需要一个即可
		EventLoopGroup workGroup  = new NioEventLoopGroup();
		//创建辅助类,和服务端的不一样,服务端的是ServerBootstrap,而客户端只是BootStrap
		Bootstrap bs = new Bootstrap();
		//加入线程组
		bs.group(workGroup)
		//指定通道类型
		.channel(NioSocketChannel.class)
		//绑定事件处理器
		.handler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel sc) throws Exception {
				//设置特殊分隔符
				ByteBuf buf  = Unpooled.copiedBuffer("$_".getBytes());
				sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
				//设置字符串形式的编码
				sc.pipeline().addLast(new StringEncoder());
				//设置字符串解码
				sc.pipeline().addLast(new StringDecoder());
				sc.pipeline().addLast(new ClientHandler());
			}
		});
		
		//链接服务端
		ChannelFuture cf = bs.connect("127.0.0.1", 8765).sync();
		//给服务端写数据,现在不再需要是写缓冲区了,因为我们上面的配置加了字符串的编码,直接写入字符串即可。
		cf.channel().writeAndFlush("服务端你好$_");  //记得加上$_,因为这个分隔符是拿来判断消息是否该发送的。
		
		//异步监听管道的关闭,如果关闭了就往下继续执行
		cf.channel().closeFuture().sync();
		workGroup.shutdownGracefully();
	}
}

客户端事件处理器ClientHandler:

public class ClientHandler extends ChannelHandlerAdapter{
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try{
			//接收服务端返回的数据
			String data = (String)msg;
			System.out.println("Client接收到的数据:"+data);
		}finally{
			//因为没有进行写操作,所以需要自己来释放
			ReferenceCountUtil.release(msg);
		}
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}
}

执行结果:

服务端的:确实完美地接收到了
Server接收到的数据:服务
Server接收到的数据:服务端
Server接收到的数据:服务端你
Server接收到的数据:服务端你好

客户端:也收到了服务端四次的回复
Client接收到的数据:客户端你好
Client接收到的数据:客户端你好
Client接收到的数据:客户端你好
Client接收到的数据:客户端你好

 

Etcd教程 — 第三章 Etcd集群动态发现、DNS发现 阅读详情

相关推荐

从EXIF到测绘:解码大疆影像元数据的实战应用指南

本文深入解析了大疆无人机影像元数据的实战价值,重点阐述了如何利用EXIF和XMP中的GPS、RTK、姿态角及相机内参等关键信息,提升测绘、三维重建及精准农业等项目的成果精度与效率。通过自动化质检脚本与行业应用场景剖析,指导从业者将元数据从信息转化为生产力,实现从拍照到专业测绘的跨越。

dell8的博客 527

DelimiterBasedFrameDecoder

分隔符与Base64编解码 1 DelimiterBasedFrameDecoder介绍 前面介绍了LineBasedFrameDecoder,其以换行符\n或者\r\n作为依据,遇到\n或者\r\n都认为是一条完整的消息。 而DelimiterBasedFrameDecoder与LineBasedFrameDecoder类似,只不过更加通用,允许我们指定任意特殊字符作为分隔符。我们还可以同时指定多个分隔符,如果在请求中发的确有多个分隔符,将会选择内容最短的一个分隔符作为依据。 例如: ..

mzjnumber1的专栏 6415

Qwen2.5-Omni实战:5分钟搞定多模态AI模型本地部署(含Thinker-Talker架构解析)

本文详细介绍了Qwen2.5-Omni多模态AI模型的本地部署流程,包括硬件配置、环境准备和实战应用开发。特别解析了其创新的Thinker-Talker架构,该架构通过TMRoPE位置编码实现跨模态同步处理,大幅提升多模态任务效率。5分钟即可完成部署,适合开发者快速实现文本、图像和音频的联合处理。

weixin_29085865的博客 172

netty粘包拆包之DelimiterBasedFrameDecoder解码器

​目录 一、 背景简介 二、应用 三、源码 一、背景简介 DelimiterBasedFrameDecoder 基于自定义分隔符解码器,他能够按照我们自定义的特殊符号或者字符作为分隔符对接收到的消息进行分段解码,在服务端接收到信息进行解析的时候DelimiterBasedFrameDecoder的构造方法需要传递两个参数maxFrameLength和可变长参数delimiters,maxFrameLength用来限制对接收到的数据进行解...

wenyixicodedog的博客 4715

告别手动打点计时:用Lauterbach TRACE32的RunTime功能,5分钟搞定嵌入式代码段性能分析

本文深入解析了Lauterbach TRACE32的RunTime功能在嵌入式代码性能分析中的革命性应用。通过硬件级计时原理和非侵入式设计,该功能能快速精确测量代码执行时间,显著提升开发效率,特别适用于汽车电子和工业控制领域。文章还提供了从基础设置到高级分析的完整实战指南,帮助工程师轻松掌握这一强大工具。

weixin_30615767的博客 279

VS2015+Qt+OpenCV+open62541开发过程(05_VS2015中使用OPCUA open62541通过Kepware读写PLC数据)

此外还需要所需lib包:WS2_32.Lib(opcua通讯用到的库,opcua使用socket通讯,需使用此库),添加#pragma comment(lib,"ws2_32.lib") 语句,有的文章说需要添加ws2_32.lib文件或ws2_32.dll到项目资源中,貌似影响不大。2.在VS中选择x64平台会报错,选择x86平台可以用,应该是ws2_32.lib相关的库不支持64位,目前没有解决,继续后面的实验,看看用Qt后是否可以解决。6.VS中建立的变量,与读取的OPC点数据类型注意对应。

zzh17的博客 1862

Netty:DelimiterBasedFrameDecoder分析

Netty:DelimiterBasedFrameDecoder分析

听海边涛声 1490

Opencv计算机视觉PPT-算法篇

01 02 03 04 05 06 07 08 09 010 011 012 013 014 015 016 017 018

Qt历险记,专注Qt技术,三年医疗设备研发经验,1年机器视觉研发经验,半年柔性传感研发经验。 204

拆帧神器:深度解读Netty中的DelimiterBasedFrameDecoder()

本文将深入研究Netty中的DelimiterBasedFrameDecoder(),这是用于处理分隔符帧的重要组件。通过生动的例子和简洁的解释,帮助读者理解DelimiterBasedFrameDecoder()的作用、如何配置,以及如何借助它轻松处理不定长度的帧。

todoitbo的博客 7875

代码复现1——Matterport3d数据集下载

进入“Dataset Download”部分,下载申请书,填写之后发送到指定邮箱(matterport3d@googlegroups.com),之后会收到回信,回信中附有一个download_mp.py的脚本文件。,大小约15G,并不是所有的Mp3d datasets,所有大小约1.3T。下载完成后如下图所示:我这边显示大小为16.1G。

qq_44100524的博客 8054

DCDC电路断电时放电波形发生震荡和电压跳变问题,如何解决?

DCDC电路断电时放电波形发生震荡和电压跳变问题: 做的一个项目需要用单片机ADC采集电压,要让单片机感应到电压降到3.1V开始往FLASH里存数据,单片机2.4V基本上就工作不了,(根据单片机手册的,擦写的时间在40mS在左右)所以3.1V降到2.4V的时间必须要大于40mS岁以上,在单片机VCC处加了一个100nF的电容,理论仿真下来150mS左右发现存不进去,用示波器抓了一下波形,发现放电时震荡很严重,实际3.1V到2.4V时间只有10ms左右,这个肯定存不进去; 请教师傅说是应该时前级DCDC开关电

**My Coding Family** 1970

Netty学习(五)-DelimiterBasedFrameDecoder

LineBasedframeDecoder属于第二种,今天我们要说的DelimiterBasedFrameDecoder和FixedLengthFrameDecoder属于第三种和第一种。DelimiterBasedFrameDecoder用来解决以特殊符号作为消息结束符的粘包问题,FixedLengthFrameDecoder用来解决定长消息的粘包问题。下面首先来用DelimiterBasedFrameDecode

rickiyang的博客 2万+

FPGA实现串口升级及MultiBoot(九)BPI FLASH相关实例演示

与SPI相关知识并没有什么太多区别(别杠硬件或者架构上),相关知识点都在上面指出,大家有什么其他需要注意点,欢迎留言讨论。关于“四样错误”就不演示了,没什么太大区别,下一讲我们开始串口升级。PS:为了扩展ICAPE2原语的使用,在原来的基础上增加了几个常用FPGA ID,并在触发启动时候增加了可选电平触发或上升/下降沿触发(例化IP时选择),新版本号V1.1。

OpenFPGA的博客 1444

netty如何处理粘包半包

netty如何处理粘包半包

SO_zxn的博客 1461

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Netty如何处理粘包与拆包?

Netty如何处理粘包与拆包?

java1234的博客 1038

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Netty对处理粘包和半包的支持

Netty对粘包和拆包的处理非常方便,有很多方法。本文介绍几种方法,并讨论优缺点,可以根据需求选择合适的

qq_36037795的博客 1248

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Netty系列-8 Netty处理粘包和半包问题

TCP协议是基于字节流的数据通讯协议,数据被看做是一连串的字节流;不具备边界信息,给接收方带来半包和粘包问题。半包:TCP传输时,将数据切割成一个个数据包进行传输。接收方一次读取操作,如果没有接受完完整的数据包而只能读取部分数据时,出现半包问题。粘包:发送方发送的两个或者多个数据包在接受方接受时被合并成了一个数据包。半包和粘包问题可以通过业务层解决。

shengyu 1402

netty半包粘包 处理_Java NIO 框架 Netty 之美:粘包与半包问题

一、前言Netty 是一个可以快速开发网络应用程序的 NIO 框架,它大大简化了 TCP 或者 UDP 服务器的网络编程。Netty 的简易和快速开发并不意味着由它开发的程序将失去可维护性或者存在性能问题,它的设计参考了许多协议的实现,比如 FTP、SMTP、HTTP 和各种二进制和基于文本的传统协议,因此 Netty 成功的实现了兼顾快速开发、性能、稳定性、灵活性为一体,不需要为了考虑一方面原因...

weixin_42237487的博客 458

Netty处理半包粘包问题

无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制。 TCP粘包/拆包发生的根本原因【流式协议,消息无边界】 粘包主要原因 发送方每次写入数据 < 套接字缓冲区大小 接收方读取套接字缓冲区数据不够及时 半包的主要原因: 发送方写入数据 > 套接字缓冲区大小 发送的数据大于协议的 MTU(Maximum Transmission Unit,最大传输单元),必须拆包 拆包、粘包示例 假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次

baidu_30130783的博客 683

Netty处理粘包与拆包

Netty提供了5种主要解决方案,用于处理在网络通信中产生的粘包(多个消息合并)和拆包(单个消息拆分)问题。

相约黄昏后 910

netty的拆包粘包,在生产中是怎么处理的

概念 TCP 是以流的方式来处理数据,所以会导致粘包 / 拆包。 拆包:一个完整的包可能会被 TCP 拆分成多个包进行发送。 粘包:也可能把小的封装成一个大的数据包发送。 原因 应用程序写入的字节大小大于套接字发送缓冲区的大小,会发生拆包现象。而应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包现象。 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。 以太网帧的 payload(净荷)大于 MTU(.

小马哥的博客 524

Netty在Android开发中的应用实战系列(四)——— 粘包 拆包 处理

本文来自阿钟的投稿,阅读大约8分钟一、什么粘包呢?简单来说就是:发送的多个包被粘到了一块变成了一个包。比如说:服务端连续发送了两个包客户端确只收到了一条包(这一个包里其实就是两个数据包)...

刘桂林 694

Netty如何处理TCP粘包/拆包问题?

Netty 提供了多种解码器来处理 TCP 粘包和拆包问题,选择合适的解码器取决于你的应用场景和消息格式。:适用于消息带有长度字段的情况。:适用于消息以特定定界符结尾的情况。:适用于消息长度固定的情况。通过合理选择和配置这些解码器,可以有效地解决 TCP 粘包和拆包问题。

qq_33240556的博客 710

Netty处理TCP半包和粘包问题

Netty在RPC中充当着重要的核心角色,封装了对JDK NIO的复杂操作。 TCP连接中存在半包和粘包问题,其历史原因不在追究,Netty在对问题处理上提供了现有的模板方法,用户需要自己定义编码和解码规则就可以处理。 LengthFieldBasedFrameDecoder这个类是用于分隔消息模板类; 假如我们规定一个TCP消息的结构如下: 1、两个字节表示消息长度; 2、剩余字节表示body内...

程序猿小窝 1888

netty之粘包分包的处理

  1、netty在进行字节数组传输的时候,会出现粘包和分包的情况。当个数据还好,如果数据量很大。并且不间断的发送给服务器,这个时候就会出现粘包和分包的情况。   2、简单来说:channelBuffer在接收包的时候,会在当时进行处理,但是当数据量一大,这个时候数据的分隔就不是很明显了。这个时候会出现数据多了或者少了的情况   3、处理的方式,一般就是...

weixin_33981932的博客 458

netty编码解码及粘包拆包处理

netty编解码 编码解码器 当你通过Netty发送或者接受一个消息的时候,就将会发生一次数据转换。入站消息会被解码:从字节转换为另一种格式(比如java对象);如果是出站消息,它会被编码成字节。 Netty提供了一系列实用的编码解码器,他们都实现了ChannelInboundHadnler或者ChannelOutboundHandler接口。在这些类中,channelRead方法已经被重写了。以入站为例,对于每个从入站Channel读取的消息,这个方法会被调用。随后,它将调用由已知解码器所提供的deco

EternitySunshine的博客 488
上一篇: NIO的Selector介绍和例子代码
下一篇: NIO编程之三次握手成功而服务器不响应客户端
Howinfun
博客等级 码龄10年 165粉丝 213原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值