【QT常用技术讲解】优化网络链接不上导致qt、qml界面卡顿的问题

news2024/12/23 13:17:40

前言

        qt、qml项目经常会涉及访问MySQL数据库、网络服务器,并且界面打开时的初始化过程就会涉及到链接Mysql、网络服务器获取数据,如果网络不通,卡个几十秒,会让用户觉得非常的不爽,本文从技术调研的角度讲解解决此类问题的socket编程方案。

调研场景一

目标:是否有成熟的第三方工具,可以通过后台命令行判断指定IP的某个端口是否在线。(其他文章分享有多线程启动第三方工具并获取结果的方法,不会导致界面卡顿)

经过调研,发现有两个工具初步满足需求:

nmap工具

格式:nmap -p [端口] [IP地址],如下所示

nmap -p 3306 192.168.1.123

如上效果图,内容较为详细,但不管端口是否在线,都花费5秒钟才能输出结果,比较影响界面的体验。

nc工具

格式:nc -zv [IP地址] [端口] -w 1            -w1是1秒钟超时

nc -zc 192.168.1.123 3306 -w1

如上效果图,加了超时参数-w1之后,确实是1秒中之内出结果,并且succeeded表示端口在线,但是当使用多线程获取此命令行返回的结果时,发现结果是空的,是在国产系统(统信UOS和麒麟kylin系统上进行的测试),然后在后台命令行进行重定向>1.txt,并且cat 1.txt时,发现输出结果也是空的,网上查资料说可能是按照的是特殊的版本,输出结果无法重定向(没有深究,因为可以调研socket编程来实现)。

socket设置超时

1、QT的QsqlDatabase

首先尝试了QsqlDatabase的超时设置方法setConnectOptions("CONNECT_TIMEOUT=1"),代码执行时提示无效。

2、原生socket的setsockopt

当无法链接上指定IP的端口时,3秒才返回,接收数据被阻塞了。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ctime>
#define qint64 std::time_t

qint64 getcurtime(){
    // 获取当前时间戳(秒级)
    std::time_t timestamp = std::time(nullptr);
    return timestamp;
}

bool checkPortOpen(const std::string& ip, int port, int timeout = 1) {
    qint64 bgtime=getcurtime();
    // 创建一个socket
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        std::cerr << "Socket creation failed!" << std::endl;
        return false;
    }

    // 设置超时参数
    struct timeval tv;
    tv.tv_sec = timeout; // 超时1秒
    tv.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));

    // 设置目标地址
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());

    // 尝试连接指定的IP和端口
    int result = connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if (result == -1) {
        qint64 endtime=getcurtime();
        std::cout << " checksqlonline use time:" << endtime-bgtime << std::endl;
        close(sock); // 连接失败,关闭socket
        return false;
    }
    qint64 endtime=getcurtime();
    std::cout << " checksqlonline use time:" << endtime-bgtime << std::endl;
    close(sock); // 连接成功,关闭socket
    return true;
}

int main(int argc, char **argv) {
    if (argc==1){
        printf("请传入参数:IP");
        return -1;
    }
    std::string ip = argv[1];  // 替换为你要检测的IP
    int port = 3306;                    // MySQL的默认端口3306

    if (checkPortOpen(ip, port)) {
        std::cout << "Port " << port << " on IP " << ip << " is open!" << std::endl;
    } else {
        std::cout << "Port " << port << " on IP " << ip << " is closed!" << std::endl;
    }

    return 0;
}

3、select异步socket

使用了异步模式,1秒以内返回,达到了优化的效果。

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <cstring>
#include <ctime>
#define qint64 std::time_t

qint64 getcurtime(){
    // 获取当前时间戳(秒级)
    std::time_t timestamp = std::time(nullptr);
    return timestamp;
}

bool checkPortOpen(const std::string& ip, int port, int timeout_sec = 1) {
    qint64 bgtime=getcurtime();
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        std::cerr << "Error creating socket." << std::endl;
        return false;
    }

    // Set socket to non-blocking mode
    fcntl(sockfd, F_SETFL, O_NONBLOCK);

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr);

    // Start connecting to the server (this will be non-blocking)
    int connect_result = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

    // Check if the connection was successful or pending
    if (connect_result < 0) {
        if (errno != EINPROGRESS) {
            std::cerr << "Connection error: " << strerror(errno) << std::endl;
            close(sockfd);
            return false;
        }
    }

    // Use select() to set a timeout for the connection
    fd_set writefds;
    FD_ZERO(&writefds);
    FD_SET(sockfd, &writefds);

    struct timeval timeout;
    timeout.tv_sec = timeout_sec;
    timeout.tv_usec = 0;

    int select_result = select(sockfd + 1, nullptr, &writefds, nullptr, &timeout);

    if (select_result > 0) {
        // Check if the socket is writable (connection succeeded)
        int so_error;
        socklen_t len = sizeof(so_error);
        getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
        if (so_error == 0) {
            // Port is open
            qint64 endtime=getcurtime();
            std::cout << " checksqlonline use time:" << endtime-bgtime << std::endl;
            close(sockfd);
            return true;
        }
    }
    qint64 endtime=getcurtime();
    std::cout << " checksqlonline use time:" << endtime-bgtime << std::endl;
    // If select result is <= 0, either timed out or failed to connect
    close(sockfd);
    return false;
}

int main(int argc, char **argv) {
    if (argc==1){
        printf("请传入参数:IP");
        return -1;
    }
    std::string ip = argv[1];  // 替换为你要检测的IP
    int port = 3306;                    // MySQL的默认端口3306

    if (checkPortOpen(ip, port)) {
        std::cout << "Port " << port << " on IP " << ip << " is open!" << std::endl;
    } else {
        std::cout << "Port " << port << " on IP " << ip << " is closed!" << std::endl;
    }

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS的学习与使用

JS的学习与使用 一 什么是Javascript&#xff1f; Javascript是一门跨平台&#xff0c;面向对象的脚本语言&#xff0c;是用来控制网页行为的&#xff0c;它能使网页可以交互 java与Javascript是完全不同的语言&#xff0c;不论是概念还是设计&#xff0c;但是基础语法类似 E…

WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇

WebRTC视频 01 - 视频采集整体架构 WebRTC视频 02 - 视频采集类 VideoCaptureModule [WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇]&#xff08;本文&#xff09; WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇 WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇 一、前…

发布rust crate

文章目录 一、cargo构建的配置类型&#xff1a;dev与release两种1.编译级别2.将 crate 发布到 Crates.io对整个库的注释pub use再导出功能发布crates.io 参考 一、cargo构建的配置类型&#xff1a;dev与release两种 $ cargo buildFinished dev [unoptimized debuginfo] targe…

Bugku CTF_Web——文件上传

Bugku CTF_Web——文件上传 进入靶场 My name is margin,give me a image file not a php抓个包上传试试 改成png也上传失败 应该校验了文件头 增加了文件头也不行 试了一下 把文件类型改成gif可以上传 但是还是不能连接 将Content-Type改大小写 再把文件后缀名改成php4 成…

三菱FX5UPLC以太网Socket通信功能

通过专用指令与通过以太网连接的对象设备以TCP及UDP协议收发任意数据的功能。 *1、是用于存储从开放的对象设备中接收到的数据的区域。 CPU模块:连接No.1~8以太网模块:连接No.1~32 以TCP协议进行通信时 TCP是在对象设备的端口号间建立连接&#xff0c;从而进行可靠的数据通信…

jmeter介绍、使用方法、性能测试、现参数化和数据驱动、分布式测试、压力测试、接口测试

目录 1.JMeter的组件介绍 2.JMeter介绍和使用方法 3.使用JMeter进行性能测试 4.JMeter如何实现参数化和数据驱动 5.使用JMeter进行分布式测试 6.使用JMeter完成压力测试 7.使用JMeter完成接口测试 下载并安装JMeter&#xff1a;从官方网站&#xff08;https://jmeter.ap…

【Android】组件化开发入门

文章目录 引入组件是什么?为什么使用组件化开发?什么是模块化&#xff0c;组件化&#xff0c;插件化&#xff1f;常见实现 组件分层创建module 组件单独调试配置组件工程类型配置组件ApplicationId和AndroidManifest文件 引入 组件是什么? 组件&#xff08;Component&#…

java访问华为网管软件iMaster NCE的北向接口时传递参数问题

上一篇文章介绍了利用《java访问华为网管软件iMaster NCE的北向接口》的一般性步骤&#xff0c;这里详细介绍其中一个读取性能数据的示例。原因是读取华为网管软件北向接口&#xff0c;完全找不到可供参考的例子。如果不需要传递什么参数&#xff0c;就能获取到结果&#xff0c…

鸿蒙 入门——ArkUI 自定义组件间的“后代“双向同步@Provide和@Consume装饰器小结(五)

文章大纲 引言一、Provide和Consume装饰器概述1、Provide和Consume关系的绑定2、使用规则3、变量的传递/访问规则4、支持的观察变化的场景5、Provide和Consume变量的值初始化和更新机制5.1、初始渲染5.2、当Provide装饰的数据变化时&#xff1a;5.3、当Consume装饰的数据变化时…

【MySQL从入门到放弃】InnoDB磁盘结构(一)

前言 从MySQL 5.5版本开始默认 使用InnoDB作为引擎&#xff0c;它擅长处理事务&#xff0c;具有自动崩溃恢复的特性&#xff0c;在日常开发中使用非常广泛。 下面是官方的InnoDB引擎架构图&#xff0c;主要分为内存结构和磁盘结构两大部分。 上一篇文章&#xff0c;我们解析了…

C哈的刷题计划之输出数字螺旋矩阵(1)

1、盲听C哈说 都说数据结构与算法是编程的核心&#xff0c;它们两个是内功与心法&#x1f600;&#xff0c;其它编程工具只是招式&#xff0c;学会了内功与心法&#xff0c;学习新事物&#xff08;这里特指层出不穷的IT技术&#xff09;就没有那么难了&#xff0c;实际上&#…

cv::RotatedRect::points误差较大

最后发现不是point的精度问题&#xff0c;float不至于产生这么大误差&#xff0c;是自己代码里缓存了顶点坐标&#xff0c;后面由手动修改了旋转矩形的角度&#xff0c;导致不匹配&#xff01; 下文可以忽略了-_-! 发现一个天坑&#xff0c;通过高宽和角度构造了一个旋转矩形 …

ThinkServer SR658H V2服务器BMC做raid与装系统

目录 前提准备 一. 给磁盘做raid 二. 安装系统 前提准备 磁盘和系统BMC地址都已经准备好&#xff0c;可正常使用。 例&#xff1a; 设备BMC地址&#xff1a;10.99.240.196 一. 给磁盘做raid 要求&#xff1a; 1. 将两个894G的磁盘做成raid1 2. 将两块14902G的磁盘各自做…

7天用Go从零实现分布式缓存GeeCache(学习)(2)

参考:https://geektutu.com/post/geecache-day2.html // Cache 是一个 LRU 缓存&#xff08;最近最少使用缓存&#xff09;&#xff0c;它不是并发安全的。 type Cache struct { maxBytes int64 // 缓存的最大字节数 nbytes int64 …

Ajax 与 Vue 框架应用点——随笔谈

老式 在老式的技术中&#xff0c;一个网页通常由前端工程师直接使用 HTML、CSS、JavaScript 编写而成 这种方式的优点很明显&#xff1a;简单粗暴&#xff0c;方便工程师以简单的思维完成工作 当然&#xff0c;缺点也很明显&#xff0c;包括但不限于&#xff1a; 直接原生开发…

鸿蒙动画开发06——打断动画

1、前 言 UI界面除了运行动画之外&#xff0c;还承载着与用户进行实时交互的功能。当用户行为根据意图变化发生改变时&#xff0c;UI界面应做到即时响应。 例如用户在应用启动过程中&#xff0c;上滑退出&#xff0c;那么启动动画应该立即过渡到退出动画&#xff0c;而不应该…

vue2和vue3的区别详解

vue2 VS vue3 对比vue2vue3配置脚手架cmd命令行可视化方式创建脚⼿架组件通信props、$emit、provide、$arrts、EventBus等props、$emit、provide、inject、arrts等数据监听watch,computedwatch,watchEffect,computed双向绑定Object.definePropertyProxyAPI⽣命周期四个阶段befo…

Spring Cloud Eureka 服务注册与发现

Spring Cloud Eureka 服务注册与发现 一、Eureka基础知识概述1.Eureka两个核心组件2.Eureka 服务注册与发现 二、Eureka单机搭建三、Eureka集群搭建四、心跳续约五、Eureka自我保护机制 一、Eureka基础知识概述 1.Eureka两个核心组件 Eureka Server &#xff1a;服务注册中心…

用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析

MVVM&#xff08;Model-View-ViewModel&#xff09;是一种架构模式&#xff0c;广泛应用于现代前端开发&#xff0c;尤其是在微软的WPF&#xff08;Windows Presentation Foundation&#xff09;应用程序中。它旨在通过将视图&#xff08;UI&#xff09;与业务逻辑&#xff08;…

飞牛云fnOS本地部署WordPress个人网站并一键发布公网远程访问

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress 前言 本文旨在详细介绍如何在飞牛云NAS上利用Docker部署WordPress&a…