成功的电商网站,jsp网站开发简单代码,网站设计的主要特点,深圳设计公司 电话前言 qt、qml项目经常会涉及访问MySQL数据库、网络服务器#xff0c;并且界面打开时的初始化过程就会涉及到链接Mysql、网络服务器获取数据#xff0c;如果网络不通#xff0c;卡个几十秒#xff0c;会让用户觉得非常的不爽#xff0c;本文从技术调研的角度讲解解决此类问…前言 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_TIMEOUT1)代码执行时提示无效。
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_tqint64 getcurtime(){// 获取当前时间戳秒级std::time_t timestamp std::time(nullptr);return timestamp;
}bool checkPortOpen(const std::string ip, int port, int timeout 1) {qint64 bgtimegetcurtime();// 创建一个socketint 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 endtimegetcurtime();std::cout checksqlonline use time: endtime-bgtime std::endl;close(sock); // 连接失败关闭socketreturn false;}qint64 endtimegetcurtime();std::cout checksqlonline use time: endtime-bgtime std::endl;close(sock); // 连接成功关闭socketreturn true;
}int main(int argc, char **argv) {if (argc1){printf(请传入参数IP);return -1;}std::string ip argv[1]; // 替换为你要检测的IPint port 3306; // MySQL的默认端口3306if (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_tqint64 getcurtime(){// 获取当前时间戳秒级std::time_t timestamp std::time(nullptr);return timestamp;
}bool checkPortOpen(const std::string ip, int port, int timeout_sec 1) {qint64 bgtimegetcurtime();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 modefcntl(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 pendingif (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 connectionfd_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 openqint64 endtimegetcurtime();std::cout checksqlonline use time: endtime-bgtime std::endl;close(sockfd);return true;}}qint64 endtimegetcurtime();std::cout checksqlonline use time: endtime-bgtime std::endl;// If select result is 0, either timed out or failed to connectclose(sockfd);return false;
}int main(int argc, char **argv) {if (argc1){printf(请传入参数IP);return -1;}std::string ip argv[1]; // 替换为你要检测的IPint port 3306; // MySQL的默认端口3306if (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;
}