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

如何解决TCP传输的“粘包“问题

关于TCP传输过程中的"粘包"问题,目前有几种常见的解决方案:
1.传输定长数据内容,接收端每次解析固定长度的数据
2.使用特殊字符作为数据包的边界,接收端解析到特殊字符则认为是一个数据包
3.使用 固定字节头部 + 不定长消息体;例如固定4字节的头部,存储的是消息体的长度,接收端解析时,先解析4个字节的头部信息,获取到消息体的长度len,再继续读取len个字节的数据,即为一个"包"


本文使用第三种方案,演示在网络编程中对发送数据进行封包 以及 接收数据时的解包 操作

QTcpSpcket 收发数据

1.发送

QTcpSocket *client = new QTcpSocket();connect(ui->btnSend,&QPushButton::clicked,[this]
{//判断是可操作,isValid表示准备好读写if(!client->isValid())return;// 模拟不同长度的数据包std::vector<std::string> vec{"1111","22222222","3333333333333333","4444444444444444444444","5555555555555555555555555555","6666666666666666666666","77777777777777777777","8888888888888","99999999999999999","00000000000000000000000"};for (auto & item : vec){sockets::TcpPacket packet(item);        // 使用TcpPacket结构包装, 添加头部长度信息client->write(packet.getData(), packet.getLenght());}
});

2.接收数据

sockets::Buffer *m_buffer = new sockets::Buffer();//收到数据,触发readyReadconnect(client,&QTcpSocket::readyRead,[this]{if (client->bytesAvailable() > 0){QByteArray recv = client->readAll();m_buffer->append(recv.data(), recv.length());while (m_buffer->readableBytes() >= sockets::TcpPacket::HEADER_LENGTH){const void* data = m_buffer->peek();int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUSconst int32_t len = sockets::util::networkToHost32(be32);if (len > 65536 || len < 0){break;	// 长度错误}else if (m_buffer->readableBytes() >= len + sockets::TcpPacket::HEADER_LENGTH){m_buffer->retrieve(sockets::TcpPacket::HEADER_LENGTH);std::string msg = m_buffer->retrieveAsString(len);qDebug() << "receive data:" << msg.c_str();}else{break;	// 不够一个完整包,等待下次接收}}}});

muduo 收发数据

    void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time){while (buf->readableBytes() >= sockets::TcpPacket::HEADER_LENGTH) // kHeaderLen == 4{// FIXME: use Buffer::peekInt32()const void* data = buf->peek();int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUSconst int32_t len = networkToHost32(be32);if (len > 65536 || len < 0){conn->shutdown();  // FIXME: disable readingbreak;}else if (buf->readableBytes() >= len + sockets::TcpPacket::HEADER_LENGTH){// 解包buf->retrieve(sockets::TcpPacket::HEADER_LENGTH);std::string msg = buf->retrieveAsString(len);std::cout << "receive data:" << msg << std::endl;// 使用Tcppacket 封包 + 发送std::string sendMsg = sockets::TcpPacket(msg).getDataAsString();conn->send(sendMsg);}else{break;          // 不够一个完整包,等待下次接收}}}
http://www.lryc.cn/news/574488.html

相关文章:

  • HTTP面试题——缓存技术
  • Qt面试题汇总
  • 记录一下小程序城市索引栏开发经历
  • ✨从零搭建 Ubuntu22.04 + Python3.11 + PyTorch2.5.1 GPU Docker 镜像并上传 Docker Hub
  • Rocky8使用gvm配置Go多版本管理的微服务开发环境
  • uni-app项目实战笔记24--uniapp实现图片保存到手机相册
  • spring01-简介
  • 618风控战升级,瑞数信息“动态安全+AI”利剑出鞘
  • window显示驱动开发—DirectX 图形基础结构 DDI
  • 【CS创世SD NAND征文】基于全志V3S与CS创世SD NAND的物联网智能路灯网关数据存储方案
  • taro小程序,tailwindcss的bg-x-x,背景颜色不生效,只有自定义的写法颜色才生效
  • C++修炼:异常
  • 解码成都芯谷金融中心文化科技产业园:文化+科技双轮驱动
  • Qt 中使用 gtest 做单元测试
  • 一文读懂微观测量:光学3D轮廓仪与共聚焦显微成像的结合应用
  • cherry-pick除了使用命令,有没有什么工具可以使用,或者更高效的方法
  • Linux 文件 I/O 与标准 I/O 缓冲机制详解
  • Java面试中被深挖过的线程问题
  • 对手机屏中断路和短路的单元进行切割或熔接,实现液晶线路激光修复原理
  • Luckysheet Excel xlsx 导入导出互相转换
  • 02-Linux内核源码编译
  • CentOS 7 编译安装Nginx 1.27.5完整指南及负载均衡配置
  • MinIO中视频转换为HLS协议并进行AES加密
  • Python Polars库详解:高性能数据处理的新标杆
  • pyqt多界面
  • LangChain网页自动化PlayWrightBrowserToolkit
  • gRPC 静态库链接到 DLL 的风险与潜在问题
  • 鸿蒙开发深入解析:Service Ability(后台任务)全面指南
  • 深度解析|智能汽车操作系统技术突破:从架构演进到产业重构
  • 比翼双飞,影像的迁徙之旅