news 2026/4/18 7:03:10

QUdpSocket的readyRead信号触发时机解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QUdpSocket的readyRead信号触发时机解析

1.QUdpSocket的readyRead信号发送的时机

QUdpSocketreadyRead()信号是在有新的 UDP 数据报到达套接字的接收缓冲区,并且应用程序尚未读取这些数据时发出的。

具体来说,其触发时机如下:


✅ 触发条件

  1. UDP 数据报已到达本地主机并被操作系统接收;
  2. 该数据报已被放入QUdpSocket的内部接收缓冲区中
  3. 当前没有正在进行的readDatagram()(或类似读取操作),即事件循环处于空闲状态;
  4. 事件循环正在运行(例如调用了QApplication::exec()QEventLoop::exec()),因为readyRead()是通过 Qt 的事件系统异步发出的。

⚠️ 注意事项

  • readyRead()不会为每个数据报单独触发一次。如果多个数据报在事件循环处理前到达,它们会堆积在缓冲区中,readyRead()只触发一次,你需要在槽函数中循环读取所有可用的数据报,直到pendingDatagramSize() == -1

    示例:

    void onReadyRead() { while (udpSocket->hasPendingDatagram()) { QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); udpSocket->readDatagram(datagram.data(), datagram.size()); // 处理 datagram } }
  • 如果你在readyRead()信号的槽函数中没有读完所有数据,不会再发出新的readyRead()信号,直到下一批新数据到来(因为 Qt 认为已有未处理的数据,无需重复通知)。

  • readyRead()是一个“提示”信号,表示“现在可以无阻塞地读取数据”,不是“每来一个包就通知一次”。

  • UDP 是无连接、不可靠协议,数据报可能丢失、乱序或重复,但readyRead()只关心“有没有可读的数据”,不保证完整性或顺序。


🔄 与 TCP (QTcpSocket) 的区别

  • QTcpSocket::readyRead()表示有字节流可读,而QUdpSocket::readyRead()表示有完整数据报可读。
  • UDP 的每次readDatagram()读取的是一个完整的数据报,不会出现“半包”问题(但可能因缓冲区太小而截断)。

总结

QUdpSocket::readyRead()至少有一个完整的 UDP 数据报已到达且尚未被读取,并且事件循环有机会处理 I/O 事件时被触发。

确保在槽函数中用while(hasPendingDatagram())循环读取全部数据,避免遗漏。

2.readDatagram接口每次读取的是一个包吗

是的,QUdpSocket::readDatagram()每次调用读取的是一个完整的 UDP 数据报(即一个“包”)


✅ 核心行为说明:

  • UDP 是面向数据报(datagram-oriented)的协议,每个发送操作(如writeDatagram())对应一个独立的数据报。
  • 接收端每次调用readDatagram()原子地读取一个完整的数据报,不会出现“半包”或“粘包”(这是与 TCP 的关键区别)。
  • 即使你传入的缓冲区比实际数据报大,也只会读取当前这一个数据报的内容;如果缓冲区太小,则多余部分会被丢弃(UDP 不支持截断后保留剩余数据)。

📌 函数原型

qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr);
  • data:用于存放接收到的数据报内容。
  • maxSize:缓冲区大小。必须 ≥ 当前待读数据报的实际大小,否则数据会被截断(且无法恢复)。
  • 可选参数addressport可获取发送方的地址和端口。

🔍 如何确保不丢数据?

  1. 先查询待读数据报的大小

    qint64 size = udpSocket->pendingDatagramSize();

    这个值就是下一个完整 UDP 包的字节数

  2. 分配足够缓冲区再读取

    QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
  3. 循环读取所有待处理数据报(因为readyRead()可能对应多个包):

    while (udpSocket->hasPendingDatagram()) { // 读取一个完整包 }

⚠️ 注意事项

  • UDP 数据报最大理论长度为 65507 字节(IPv4 下:65535 - IP头20 - UDP头8),但实际受网络 MTU 限制(通常 ≤ 1500 字节)。若应用可能收大包,需确保缓冲区足够。
  • 如果maxSize < pendingDatagramSize()超出部分会被静默丢弃,且无法得知是否发生截断(除非你对比readDatagram()返回值与pendingDatagramSize())。
  • 每次readDatagram()调用只消耗接收队列中的一个数据报。

✅ 总结

readDatagram()每次读取且仅读取一个完整的 UDP 数据报,这是由 UDP 协议本身的“消息边界保留”特性决定的。正确使用pendingDatagramSize()配合循环读取,可安全高效地处理所有到达的数据包。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 4:44:32

基于STM32单片机智能环境监控温湿度CO2光照PM2.5无线设计26-029

26-029、STM32智能环境监控系统设计-TFT1.44-PM2.5-CO2-BH1750-DHT11-WIFI-风扇本设计由STM32F103C8T6单片机核心板电路TFT1.44寸液晶电路PM2.5传感器电路CO2传感器电路BH1750光照检测电路DHT11温湿度传感器电路2路风扇电路WiFi-ESP8266模块电路电源电路组成。1、TFT1.44寸液晶…

作者头像 李华
网站建设 2026/4/17 18:39:28

达梦数据库部署安装故障一

你执行 disql 登录达梦数据库时出现 [-70028]:创建SOCKET连接失败 报错&#xff0c;核心原因是 达梦数据库实例&#xff08;dmserver&#xff09;尚未启动&#xff0c;或实例未正常监听 5236 端口&#xff0c;导致 disql 无法建立 Socket 连接&#xff0c;具体分析和解决方案如…

作者头像 李华
网站建设 2026/3/22 23:04:29

智能蛋糕店管理系统的设计与实现

一、选题背景及意义. 1.选题背景 随着现代社会经济的快速发展和人们生活水平的不断提高,烘焙食品特别是蛋糕产品已经从过去的奢侈品转变为日常消费品,蛋糕店作为重要的零售业态在城市商业中占据着越来越重要的地位。然而,传统蛋糕店在经营管理过程中普遍面临着诸多挑战,包括订单…

作者头像 李华
网站建设 2026/4/18 5:43:16

新手站长别哭!三个月把网站流量干翻倍的老炮儿碎碎念

新手站长别哭&#xff01;三个月把网站流量干翻倍的老炮儿碎碎念 新手站长别哭&#xff01;三个月把网站流量干翻倍的老炮儿碎碎念咱先把丑话说前头&#xff1a;SEO 真不是玄学&#xff0c;但比玄学还磨人关键词&#xff1a;别一上来就“口红口红口红”&#xff0c;先学会“装无…

作者头像 李华
网站建设 2026/4/3 1:30:43

可解释集成模型如何提升商品搜索效果

可解释集成模型改进商品检索 机器学习领域正飞速发展&#xff0c;新模型层出不穷&#xff0c;均承诺超越前代。然而&#xff0c;为特定用例评估新模型是一个耗时且消耗资源的过程。这对于像某中心的商店这样承诺为客户提供最先进技术、同时又全天候高负载运营的在线服务而言&am…

作者头像 李华