当前位置: 首页 > article >正文

TCP粘/拆包----自定义消息协议

今天是2024年12月31日,今年的最后一天,希望所有的努力在新的一年会有回报。❀

无路可退,放弃很难,坚持很酷

TCP传输

是一种面向二进制的,流的传输。在传输过程中最大的问题是消息之间的边界不明确。而在服务端主要的问题就是读取TCP连接的时候,不确定一次会读到多少数据

TCP会使用某些算法如Nagle,将多个量小,独立的数据包合并为一个报文段(大包)进行发送,以提高效率,而这些独立的数据之间没有明确的边界,服务端会出现几种情况

假如报文段中有两个独立的数据包AB,较理想的情况是服务端分别读取到了这两个包[A],[B]。

其次服务端把这两个包作为一个整体读取到了,此时这两个包成为一个整体状态[AB],即粘包

服务端读取到了整个A包,以及B包的一部分,此时就发生了拆包

还可能会有其他原因,比如发送的数据包,超过了最大报文段的长度MSS(1460byte),此时大包也会被拆包。

说到底都是因为TCP传输是基于字节流进行传输的,不会维护消息之间的边界

解决方案:

自定义消息传输协议,在消息前加一个长度,服务端按长度读取。

自定义一个消息传输的协议对象,后续的编解码都基于此

配置服务端,客户端启动:依旧是按照Netty那套模型来....省略

主要是需要自定义一个编解码器,因为传输的是自定义的对象,而Netty默认的channelHandler只会传输字节流数据。需要手动编解码进行处理。

出站编码器:

write方法会将对象数据以字节的形式写入byteBuf并发送

(编码器只会对规定的数据类型进行编码,类型外直接发送)

入站解码器:

解码器接收到的是字节流,将它转为消息对象。

readInt会先读取长度,再根据长度去读取字节内容

解码完成后通过list交给下一个handler处理

ReplayingDecoder 会自动缓存字节数据并管理读取指针。如果数据还没读取完,它会在下次调用 decode() 时继续从正确的位置读取,而你不需要手动管理指针的移动。无需手动判断readableBytes了,它会根据协议和读取的字节自动管理数据的边界

 Void 就是一个占位符,表示无需任何状态(如当前解码的消息长度、已读取的字节数等对象,可在后续解码过程中继续处理)来辅助解码过程。

将编码器以及处理器依次加入到channel的pipeLine

双方处理流程: 

1,处理器发送消息对象,消息传递给下一个handler即编码器,编码为字节流然后网络发送。

2,解码器收到网络二进制消息流,解码为消息对象,传递给下一个handler处理消息。

现在客户端发送了十个消息对象,为了方便看问题,加一个计数器统计消息的数量:

刚好十条。

如果粘包或者拆包的话,就不会打印出十条消息数量,如这种情况:


http://www.kler.cn/a/460656.html

相关文章:

  • aardio —— 虚表 —— 模拟属性框
  • OpenHarmony通过挂载镜像来修改镜像内容,RK3566鸿蒙开发板演示
  • 碰一碰拓客系统:创新引领智能拓客新纪元
  • 数字化供应链创新解决方案在零售行业的应用研究——以开源AI智能名片S2B2C商城小程序为例
  • 实践:事件循环
  • [算法] [leetcode-324] 摆动排序 II
  • Python 的 abc 模块 抽象基类(Abstract Base Classes)
  • 建造者模式详解
  • Java - 日志体系_Apache Commons Logging(JCL)日志接口库_桥接Logback 及 源码分析
  • 04、JUC并发编程之:简单概述(四)
  • pg_wal 目录下 wal 日志文件异常累积过大
  • 慧眼识词:解析TF-IDF工作原理
  • python爬虫--小白篇【selenium自动爬取文件】
  • 微信小程序自定义表格样式
  • 2024年度总结
  • 前端多个项目部署在同一个nginx下,前缀不同,配置编写方式
  • 红黑树的左旋右旋
  • MySQL 执行计划:优化查询性能
  • 家政预约小程序04活动管理表结构设计
  • Mac安装Jupyter和nbextensions报错问题
  • OpenStack系列第四篇:云平台基础功能与操作(Dashboard)
  • Spring 创建和管理 Bean 的原理,以及Spring 的单例模式是否线程安全?(有无状态Bean)
  • 电子电器架构 --- 智能座舱与AI结合
  • 数据仓库工具箱—读书笔记02(Kimball维度建模技术概述05、处理缓慢变化维度SCD属性)
  • 基于深度学习的医疗问诊助手
  • Postman[3] 创建Get和Post请求