Qt低版本多网卡组播bug
原文地址
最近在某个项目中,发现了一个低版本Qt的bug,导致组播无法正常使用,经过一番排查,终于找到了原因,特此记录。
环境
- Qt:5.7.0 mingw32
- 操作系统:windows 11
现象
在Qt5.7.0版本中,使用组播发送数据时,发现数据无法接收,经过长时间的排查,发现是Qt的bug,具体现象如下:
- 在Qt5.7.0版本中,使用组播发送数据时,发现数据无法接收。
- 使用串口调试工具,发现发送的数据包没有问题(无论何种情况都可以)。
- 使用wireshark抓包,发现发送的数据包没有问题。
- 使用Qt自带的组播收发例子,本机测试发现可以正常接收数据,但是当收发处于两台电脑时不能接收。
排查步骤
-
使用调试工具
- 使用地址 0.0.0.0: port 不能接收到数据
- 使用地址 192.168.1.100: port 可以接收到数据
- 使用地址 239.255.255.255: port 不能接收到数据
-
测试自带的组播收发例子
- 本机测试可以正常接收数据
- 两台电脑测试不能接收数据
尝试解决
经过一顿搜索,加上长时间的摸索(本机的虚拟网卡太多),长时间折腾后发现只有一个网卡的时候可以正常。必须祭出终极大杀器 socket sdk 如果还不行都不知道该怎么办了,结果测试竟然可行
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")void sendData(SOCKET sock)
{struct sockaddr_in dest_addr; // 目标地址结构体// 设置目标地址memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family = AF_INET; // IPv4dest_addr.sin_port = htons(groupPort); // 目标端口号dest_addr.sin_addr.s_addr = inet_addr(groupIp); // 目标IP地址char *sendData = "hello world";sendto(sock, sendData, strlen(sendData), 0, (const struct sockaddr *)&dest_addr, sizeof(dest_addr));
}int main(int argc, char* argv[])
{unsigned short groupPort = 37080;char *bindIp = "192.168.8.112";char *localIp = "192.168.8.112";char *groupIp = "239.255.255.250";printf("%s\n%s\n%s\n%d\n", bindIp, localIp, groupIp, groupPort);if(argc >= 5){bindIp = argv[1];localIp = argv[2];groupIp = argv[3];groupPort = atoi(argv[4]);}int iRet = 0;WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = inet_addr(bindIp);//INADDR_ANY;//addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");addr.sin_port = htons(groupPort);bool bOptval = true;iRet = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptval, sizeof(bOptval));if (iRet != 0) {printf("setsockopt fail:%d", WSAGetLastError());return -1;}iRet = bind(sock, (sockaddr*)&addr, sizeof(addr));if (iRet != 0) {printf("bind fail:%d\n", WSAGetLastError());return -1;}printf("socket:%d bind success\n", sock);ip_mreq multiCast;multiCast.imr_interface.S_un.S_addr = inet_addr(localIp);multiCast.imr_multiaddr.S_un.S_addr = inet_addr(groupIp);iRet = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multiCast, sizeof(multiCast));if (iRet != 0) {printf("setsockopt fail:%d\n", WSAGetLastError());return -1;}printf("udp group start: %d, %d\n", IPPROTO_IP, IP_ADD_MEMBERSHIP);int len = sizeof(sockaddr);char strRecv[1024] = { 0 };while (true){memset(strRecv, 0, sizeof(strRecv));iRet = recvfrom(sock, strRecv, sizeof(strRecv) - 1, 0, (sockaddr*)&addr, &len);if (iRet <= 0) {printf("recvfrom fail:%d", WSAGetLastError());return -1;}printf("recv data:%s\n", strRecv);}closesocket(sock);WSACleanup();return 0;
}
经过对比发现Qt的源码中地址 mreq4.imr_interface.s_addr 赋值时候 QHostAddress firstIP = addressEntries.first().ip();可能为IPV6地址,导致IPV6地址赋值给IPV4地址,导致组播失败。
if (iface.isValid()) {const QList<QNetworkAddressEntry> addressEntries = iface.addressEntries();if (!addressEntries.isEmpty()) {QHostAddress firstIP = addressEntries.first().ip();mreq4.imr_interface.s_addr = htonl(firstIP.toIPv4Address());} else {d->setError(QAbstractSocket::NetworkError,QNativeSocketEnginePrivate::NetworkUnreachableErrorString);return false;}} else {mreq4.imr_interface.s_addr = INADDR_ANY;}
解决方案
- 更新Qt版本,最新版的Qt已经修复了这个问题
if (iface.isValid()) {const QList<QNetworkAddressEntry> addressEntries = iface.addressEntries();bool found = false;for (const QNetworkAddressEntry &entry : addressEntries) {const QHostAddress ip = entry.ip();if (ip.protocol() == QAbstractSocket::IPv4Protocol) {mreq4.imr_interface.s_addr = htonl(ip.toIPv4Address());found = true;break;}}if (!found) {d->setError(QAbstractSocket::NetworkError,QNativeSocketEnginePrivate::NetworkUnreachableErrorString);return false;}} else {mreq4.imr_interface.s_addr = INADDR_ANY;}
- 修改代码如下
在工程文件中添加
win32 {LIBS += -lWs2_32
}
修改关键代码
//添加头文件
#ifdef Q_OS_WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
//...........................//Qt 5.7 bug fix, 第一个IP可能为ip v6if (firstIP.protocol() == groupAddress.protocol()) {ok = udpsock->joinMulticastGroup(groupAddress, iface);} else {
#ifdef Q_OS_WIN32for (int i = 0; i < addressEntries.size(); i++) {QHostAddress addrTemp = addressEntries.at(i).ip();if (addrTemp.protocol() == groupAddress.protocol()) {ip_mreq multiCast;multiCast.imr_interface.S_un.S_addr = inet_addr(addrTemp.toString().toUtf8().constData());multiCast.imr_multiaddr.S_un.S_addr = inet_addr(groupAddress.toString().toUtf8().constData());int res = setsockopt(udpsock->socketDescriptor(),0,12,(char *) &multiCast,sizeof(multiCast));ok = (res == 0);break;}}
#elseok = udpsock->joinMulticastGroup(groupAddress, iface);
#endif
血的经验
- 使用三方标准工具测试
- 使用原始sdk测试
- Qt也可能存在bug
- 搜索引擎可能存在误导
- csdn === 田文镜
相关文章:
Qt低版本多网卡组播bug
原文地址 最近在某个项目中,发现了一个低版本Qt的bug,导致组播无法正常使用,经过一番排查,终于找到了原因,特此记录。 环境 Qt:5.7.0 mingw32操作系统:windows 11 现象 在Qt5.7.0版本中&…...
Leetcode:540. 有序数组中的单一元素
题目 给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。 请你找出并返回只出现一次的那个数。 你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。 输入: nums [1,1,2,3,3,4,4,8,8] 输出: 2 输入:…...
Python数据分析NumPy和pandas(二十七、数据可视化 matplotlib API 入门)
数据可视化或者数据绘图是数据分析中最重要的任务之一,是数据探索过程的一部分,数据可视化可以帮助我们识别异常值、识别出需要的数据转换以及为模型生成提供思考依据。对于Web开发人员,构建基于Web的数据可视化显示也是一种重要的方式。Pyth…...
数组指针和指针的区别
区分数组指针和指针数组 int *p[3]和 int (*p)[3] 根据运算符的优先级,"[]"的优先级是高于“*”的,p就会先与[]结合,那么它本质就是数组,数组内存放的是指针,它叫指针数组。(int*p[3]ÿ…...
Linux git-bash配置
参考资料 命令提示符Windows下的Git Bash配置,提升你的终端操作体验WindowsTerminal添加git-bash 目录 一. git-bash配置1.1 解决中文乱码1.2 修改命令提示符 二. WindowsTerminal配置git-bash2.1 添加git-bash到WindowsTerminal2.2 解决删除时窗口闪烁问题 三. VS…...
【后端速成Vue】computed计算属性
前言: 本期将会介绍 Vue 中的计算属性,他和 methods 方法又会有什么区别呢?在这里都会给你一一讲解。 篮球哥找工作专属IT岗位内部推荐: 专属内推链接:内推通道 1、computed计算属性 概念: 基于现有的数据…...
力扣-每日温度
. - 力扣(LeetCode) 这是我的第一个思路 虽然可以得到正确答案 但是过于暴力 已经超出了时间限制 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {vector<int>ans;for (int i 0; i <…...
(Go语言)初上手Go?本篇文章帮拿捏Go的数据类型!
1. bool 类型 布尔类型:只有 true 和 false 两种值 在Go中,整数 0 不代表 false 值,1也不代表 true 值 即数字无法代替布尔值进行逻辑判断,两者是完全不同的类型 布尔类型占用 1 字节 2. int 整型 Go中为不同位数的整数分配…...
支付宝域名如何加入白名单(扫码老是弹窗)
支付宝扫码之后,遇到非支付宝官方网页,请确认是否继续访问弹窗,问题解决办法。 本章教程提供解决办法,亲测有效。 一、打开支付宝开放平台 登录地址:https://open.alipay.com/ 然后进行扫码登录。 1、打开网页/移动应用开发 2、前往创建 3、创建应用...
嵌入式学习第21天Linux基础
目录 第1章 Linux 系统介绍 1.1 Unix 操作系统(了解) 1.2 Linux 操作系统(了解) 1.3 Linux 操作系统的主要特性(重点) 1.4 Linux 与 Unix 的区别与联系 1.5 GUN 与 GPL(了解) …...
【activiti工作流源码集成】springboot+activiti+mysql+vue+redis工作流审批流集成整合业务绑定表单流程图会签驳回
工作流集成实际项目案例,demo提供 源码获取方式:本文末个人名片直接获取。 前言 activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,请假审批demo从流程绘制到审批结束实例。 一、项目形式 springbootvue…...
华为私有接口类型hybrid
华为私有接口类型hybrid Tip:hybrid类型,简称混合型接口。 本次实验模拟2层网络下 vlan10 vlan20 不能互访,vlan10 vlan20 同时可以访问vlan100 sw1配置如下: <Huawei>sy [Huawei]sys sw1 [sw1]vl ba 10 20 100 [sw1]int…...
计算机的错误计算(一百五十)
摘要 探讨 MATLAB 中 的计算精度问题。当 为含有小数的大数或 ()附近数时,输出会有错误数字。 例1. 已知 计算 直接贴图吧: 另外,16位的正确值分别为 -0.7882256119904400e0、0.1702266977524110e0、-0.…...
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
在前端开发中,模块化是一个重要的概念,不同的模块化标准有不同的特点和适用场景。webpack 同时支持 CommonJS 和 ES6 Module,因此需要理解它们在互操作时 webpack 是如何处理的。 同模块化标准 如果导出和导入使用的是同一种模块化标准&…...
工程认证与Spring Boot:计算机课程管理的新探索
摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于工程教育认证的计算机课程管理平台的开发全过程。通过分析基于工程教育认证的计算机课程管理平台管理的不足,创建了一个计算机管理基于工程教育认…...
vue3的自定义hooks怎么写?
写个hook函数去追踪鼠标位置: 没用hook前: <script setup> import { ref, onMounted, onUnmounted } from vueconst x ref(0) const y ref(0)function update(event) {x.value event.pageXy.value event.pageY }onMounted(() > window.ad…...
SpringBoot项目编译报错 类文件具有错误的版本 61.0, 应为 52.0
springboot项目在编译时报错: /Users/Apple/Developer/art/caicai/cai-api/dubbo-samples/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider/src/main/java/org/apache/dubbo/springboot/demo/provider/ProviderApplication.java:22:32 java…...
【网络】应用层——HTTP协议
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解什么是HTTP协议。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自:网络 &g…...
ServletContext介绍
文章目录 1、ServletContext对象介绍1_方法介绍2_用例分析 2、ServletContainerInitializer1_整体结构2_工作原理3_使用案例 3、Spring案例源码分析1_注册DispatcherServlet2_注册配置类3_SpringServletContainerInitializer 4_总结 ServletContext 表示上下文对象,…...
让AI帮我用java实现EasyExel读取图片—支持WPS嵌入图片
🌈 场景概述 java 小伙伴相信都使用 EasyExcel 以及 POI 库实现过 Excel 批量导入、导出功能,但只有部分人实现过 excel 导入带图片数据的场景。这个技术实现手段网上也有很多案例和demo,最常见的就是通过 XSSFPictureData 来实现。但是在 W…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
