Netty进阶——粘包与半包(代码示例)

news/2024/3/29 9:11:14/文章来源:https://blog.csdn.net/li1325169021/article/details/128106437

目录

    • 一、消息粘包和消息半包的概述
      • 1.1、消息粘包
      • 1.2、消息半包
    • 二、粘包现象代码示例
      • 2.1、粘包现象服务端示例代码
      • 2.2、粘包现象客户端示例代码
      • 2.3、分别启动服务端,客户端,查看服务端结果输出
    • 三、半包现象代码示例
      • 3.1、半包现象服务端示例代码
      • 3.2、半包现象客户端示例代码
      • 3.3、分别启动服务端,客户端,查看服务端结果输出

一、消息粘包和消息半包的概述

1.1、消息粘包

  • 当缓冲区足够大,由于网络不稳定种种原因,可能会有多条消息从通道读入缓冲区,此时如果无法分清数据包之间的界限,就会导致粘包问题。

1.2、消息半包

  • 若消息没有接收完,缓冲区就被填满了,会导致从缓冲区取出的消息不完整,即半包的现象。

二、粘包现象代码示例

2.1、粘包现象服务端示例代码

  • 服务端代码

    package com.example.nettytest.netty.day5;import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import lombok.extern.slf4j.Slf4j;/*** @description:   Netty粘包现象演示服务端*                 消息粘包:当缓冲区足够大,由于网络不稳定种种原因,可能会有多条消息从通道读入缓冲区,*                         此时如果无法分清数据包之间的界限,就会导致粘包问题;* @author: xz*/
    @Slf4j
    public class NettyServerTest {public static void main(String[] args) {new NettyServerTest().start();}void start() {NioEventLoopGroup boss = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap().channel(NioServerSocketChannel.class).group(boss, worker).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {//会在连接channel建立成功后,触发active事件@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("connected>>>>>>>>>>>>>>>> {}", ctx.channel());super.channelActive(ctx);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {log.debug("disconnect>>>>>>>>>>>>>>>> {}", ctx.channel());super.channelInactive(ctx);}});}});ChannelFuture channelFuture = serverBootstrap.bind(8080);log.debug("{}>>>>>>>>>>>>>>>> binding...", channelFuture.channel());channelFuture.sync();log.debug("{}>>>>>>>>>>>>>>>> bound...", channelFuture.channel());channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("server error", e);} finally {boss.shutdownGracefully();worker.shutdownGracefully();log.debug(">>>>>>>>>>>>>>>>stoped");}}
    }
    

2.2、粘包现象客户端示例代码

  • 客户端代码示例

    package com.example.nettytest.netty.day5;import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import lombok.extern.slf4j.Slf4j;
    /*** @description: Netty粘包现象演示客户端* @author: xz*/
    @Slf4j
    public class NettyClientTest {public static void main(String[] args) {new NettyClientTest().start();}void start() {NioEventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap().channel(NioSocketChannel.class).group(worker).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {log.debug("connetted》》》》》》》》》》》》》》》");ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {//会在连接channel建立成功后,触发active事件@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("遍历 sending 每次发送16个字节》》》》》》》》》》》》》》》");for (int i = 0; i < 10; i++) {//设置缓冲区大小16个字节ByteBuf buffer = ctx.alloc().buffer(16);buffer.writeBytes(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});ctx.writeAndFlush(buffer);}}});}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("client error", e);} finally {worker.shutdownGracefully();}}
    }
    

2.3、分别启动服务端,客户端,查看服务端结果输出

  • 先启动服务端
    在这里插入图片描述
  • 再启动客户端
    在这里插入图片描述
  • 再次查看服务端
    注:可下图输出结果可知:服务器端的某次输出,可以看到一次就接收了 160 个字节,而非分 10 次接收。在这里插入图片描述

三、半包现象代码示例

3.1、半包现象服务端示例代码

  • 为现象明显,服务端添加一下接收缓冲区,其它代码不变

    serverBootstrap.option(ChannelOption.SO_RCVBUF, 10);
    
  • 服务端完整示例代码

    package com.example.nettytest.netty.day5;import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import lombok.extern.slf4j.Slf4j;
    /*** @description:   Netty半包现象演示服务端*                 消息半包:若消息没有接收完,缓冲区就被填满了,会导致从缓冲区取出的消息不完整,即半包的现象。* @author: xz*/
    @Slf4j
    public class NettyServerTest1 {public static void main(String[] args) {new NettyServerTest().start();}void start() {NioEventLoopGroup boss = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap().channel(NioServerSocketChannel.class)//服务端添加接收缓冲区,大小设置10.option(ChannelOption.SO_RCVBUF, 10).group(boss, worker).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("connected================== {}", ctx.channel());super.channelActive(ctx);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {log.debug("disconnect================== {}", ctx.channel());super.channelInactive(ctx);}});}});ChannelFuture channelFuture = serverBootstrap.bind(8080);log.debug("{} binding====================", channelFuture.channel());channelFuture.sync();log.debug("{} bound====================", channelFuture.channel());channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("server error", e);} finally {boss.shutdownGracefully();worker.shutdownGracefully();log.debug("stoped======================");}}
    }
    

3.2、半包现象客户端示例代码

  • 客户端代码示例无变化,完整代码如下

    package com.example.nettytest.netty.day5;import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import lombok.extern.slf4j.Slf4j;
    /*** @description: Netty半包现象演示客户端* @author: xz*/
    @Slf4j
    public class NettyClientTest1 {public static void main(String[] args) {new NettyClientTest1().start();}void start() {NioEventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap().channel(NioSocketChannel.class).group(worker).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {log.debug("connetted----------------");ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {//会在连接channel建立成功后,触发active事件@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.debug("sending----------------");for (int i = 0; i < 10; i++) {ByteBuf buffer = ctx.alloc().buffer(16);buffer.writeBytes(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});ctx.writeAndFlush(buffer);}}});}});ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {log.error("client error", e);} finally {worker.shutdownGracefully();}}
    }
    

3.3、分别启动服务端,客户端,查看服务端结果输出

  • 先启动服务端
    在这里插入图片描述
  • 再启动客户端
    在这里插入图片描述
  • 再次查看服务端
    注:可下图输出结果可知:服务器端的某次输出,可以看到接收的消息被分为两节,第一次 16 字节,第二次 32 字节,第三次 64 字节,第四次 48 字节
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_39008.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【强化学习论文】小样本策略泛化的提示决策转换器

文献题目&#xff1a;Prompting Decision Transformer for Few-Shot Policy Generalization 摘要 人类可以利用先前的经验并从少量演示中学习新任务。与旨在通过更好的算法设计实现快速适应的离线元强化学习相比&#xff0c;我们研究了架构归纳偏差对少样本学习能力的影响。我…

不懂单链表? 这篇文章就帮你搞明白

坚持看完&#xff0c;结尾有思维导图总结 链表对指针的操作要求不低链表的概念链表的特性链表的功能(最重要)定义和初始化头插头删细节说明尾插尾删寻找链表元素与打印链表在 某位置后插入删除在某位置的插入删除销毁链表链表的概念 什么是链表 官方概念&#xff1a;链表是一种…

显卡---显卡驱动---CUDA---Cudnn

1. 背景 最近在follow百度的CAE这篇论文时&#xff0c;源码需要的环境为&#xff1a; python 3.7 cuda: 11.0 cudnn: 8.0.4 gcc 8.2 该版本要求与我目前使用的服务器上的CUDA版本不相符合。因此搜索了一篇国外小哥的文章&#xff0c;讲述了如何在一台服务器上安装多个CUDA和Cud…

Node之Express学习笔记

一.Express 1.1什么是Express Express的作用和Node.js内置的http模块类似 专门用来创建Web服务器的 本质&#xff1a;npm上的第三方包&#xff0c;提供快速创建Web服务器的便捷方法 1.2Express能做什么 Web网站服务器&#xff1a;专门提供Web网页资源的服务器 API接口服务器&…

FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)

1、大家好&#xff0c;今天给大家带来的内容是&#xff0c;基于AXI4协议的采用AXI-HP通道完成PL侧数据发送至PS侧&#xff08;PS侧数据发送至PL侧并没有实现&#xff0c;但是保留了PL读取PS测数据的接口&#xff09; 2、如果大家用到SoC这种高级功能&#xff0c;那大家应该对于…

Linux进阶-进程间通信(ipc)

进程间通信&#xff1a;数据传输、资源共享、事件通知、进程控制。 Linux系统下的ipc 早期unix系统 ipc&#xff1a;管道&#xff08;数据传输&#xff09;、信号&#xff08;事件通知&#xff09;、fifo&#xff08;数据传输&#xff09;。 system-v ipc&#xff08;贝尔实…

Kubernetes之Pod初始化容器

Kubernetes之Pod初始化容器 概述 ​ 初始化是很多编程语言普遍关注的问题&#xff0c;甚至有些编程语言直接支持模式构造来生成初始化程序&#xff0c;这些用于进行初始化的程序结构称为初始化器或初始化列表。初始化代码要首先运行&#xff0c;且只能运行一次&#xff0c;它们…

CAPM资产定价模型

本文是Quantitative Methods and Analysis: Pairs Trading此书的读书笔记。 CAPM(Capital Asset Pricing Model)资产定价模型 这个模型在金融界的影响就是beta这个词的使用。CAPM模型用两个部分的回报之和来解释一个资产的回报。其中一个部分是指市场&#xff08;称为market)…

时间序列:时间序列模型---自回归过程(AutoRegressive Process)

本文是Quantitative Methods and Analysis: Pairs Trading此书的读书笔记。 这次我们构造一个由无限的白噪声实现&#xff08;white noise realization) 组成的时间序列&#xff0c;即。这个由无限数目的项组成的值却是一个有限的值&#xff0c;比如时刻的值为&#xff0c; 而…

Magic Leap 2设计和开发幕后花絮

Magic Leap今年发布新款AR头显Magic Leap 2&#xff0c;相比于上一代Magic Leap 1&#xff0c;新品更专注于B端场景&#xff0c;自公布以来&#xff0c;Magic Leap不仅对公司策略、理念更加透明&#xff0c;也不断公开ML2产品设计背后的思考。相比于ML1&#xff0c;ML2的设计有…

粒子群算法查找函数最小值

实现 函数 F01、F06 的优化测试 以下内容是现有算法的运行结果、调参分析、及代码实现&#xff0c;用于给其他人提供参考&#xff0c;懒得改了hh 1. 运行结果 参数 w 0.5 &#xff08;可更改&#xff09; c1 2.0 &#xff08;可更改&#xff09; c2 2.0 &#xff08;可更改&…

Echart 柱状图,X轴斜着展示

option { color: [‘#3398DB’], tooltip: { trigger: ‘axis’, axisPointer: { // 坐标轴指示器&#xff0c;坐标轴触发有效 type: ‘shadow’ // 默认为直线&#xff0c;可选为&#xff1a;‘line’ | ‘shadow’ } }, grid: { left: ‘3%’, right: ‘4%’, bottom: ‘3%’…

iPhone升级iOS 16后出现提示“面容ID不可用”怎么办?

最近&#xff0c;很多用户在苹果社区反馈&#xff0c;iPhone升级iOS 16后Face ID不能用了&#xff0c;尝试重置Face ID时&#xff0c;系统会弹窗提示“面容ID不可用&#xff0c;稍后尝试设置面容ID。” 如果你的iPhone在没有摔落手机或是手机进水的情况下出现这个弹窗&#xff…

【uniapp小程序】路由跳转navigator传参封装

文章目录&#x1f34d;前言&#x1f34b;正文1、看官网1.1 navigator API 介绍1.2、路由跳转参数传递1.3、五种常见的跳转方式1.3.1 uni.navigateTo(OBJECT)1.3.2 uni.redirectTo(OBJECT)1.3.3 uni.reLaunch(OBJECT)1.3.4 uni.switchTab(OBJECT)1.3.5 uni.navigateBack(OBJECT)…

图的初识·基本概念

文章目录基本概念图有两种基本形式无向图的表示有向图的表示基本概念 图结构也是数据结构的一部分。而且还有一点小难。图是由多个结点链接而成的&#xff0c;但是一个结点可以同时连接多个其他结点&#xff0c;多个节点也可以同时指向一个节点。【多对多的关系】 图结构是任意…

如何从报表控件FastReport .NET中连接到 PostgreSQL 数据库?

FastReport.NET官方版下载 Fastreport是目前世界上主流的图表控件&#xff0c;具有超高性价比&#xff0c;以更具成本优势的价格&#xff0c;便能提供功能齐全的报表解决方案&#xff0c;连续三年蝉联全球文档创建组件和库的“ Top 50 Publishers”奖。 慧都科技是Fast Repor…

mysql索引类别和失效场景

首先&#xff0c;我们为什么要使用索引&#xff0c;索引有什么作用呢&#xff1f; 索引可以用来快速查询数据表中有某一特定值的记录&#xff0c;大大加快数据的查询速度&#xff1b;在列上创建了索引之后&#xff0c;查找数据时可以直接根据该列上的索引找到对应记录行的位置…

YOLO X 改进详解

YOLO X 主要改进&#xff1a; Anchor-Free: FCOSDecoupled detection headAdvanced label assigning strategy Network structure improvement Decoupled detection head 对比于YOLO V5, YOLO X 在detection head上有了改进。YOLO V5中&#xff0c;检测头是通过卷积同时预…

视频编解码 - RTP 与 RTCP

目录 RTP 实时传输协议 RTCP协议 将H264 RTP打包 RTP 实时传输协议 音视频数据传输&#xff0c;先将原始数据经过编码压缩后&#xff0c;将码流打包成一个个RTP包&#xff0c;再将码流传输到接收端。 打包的作用 接收端要正确地使用这些音视频编码数据&#xff0c;不仅仅需…

JaVers:自动化数据审计

在开发应用程序时&#xff0c;我们经常需要存储有关数据如何随时间变化的信息。此信息可用于更轻松地调试应用程序并满足设计要求。在本文中&#xff0c;我们将讨论 JaVers 工具&#xff0c;该工具允许您通过记录数据库实体状态的更改来自动执行此过程。 Javers如何工作&#x…