【QT性能优化】QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器:QT是否适合做高性能网络应用?补天云这个视频告诉你在大厂Linux云服务器上的实测结果
QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器
Ø 简介
本文作者编写了一套基于QT的TCP网络服务器程序和基于QT的TCP客户端程序,在某大厂的云服务器上进行了C1000K的实际测试。实测结果表明QT的网络模块足以支持开发常规业务的百万TCP长连接的高性能高并发网络服务器应用。整个测试程序主要使用了QT网络模块提供的QTcpServer和QTcpSocket这两个类型。
文章目录
正文
Ø QT网络模块百万连接高性能高并发服务器应用实例效果
服务器配置
最近为了测试QT框架的网络模块在高性能高并发网络服务器应用领域的具体表现,搞了一台某大厂的云服务器,具体配置是64位CentOS8+16核CPU+64GB内存+50GB SSD+100MB外网网络带宽+10GB内网带宽;在服务器上安装了gcc/g++以及QT6.4。
可能有人会有困惑,使用这样配置的云服务器做这样的C1000K测试,是不是很贵呢?实际上云服务器一般的主机支持包月模式和按小时计费模式,网络流量支持固定带宽模式和按实际流量计费的模式。按小时计费模式也就是随用随开不用随时退还。本次测试过程持续几个小时花费了十几块RMB。
测试程序
服务器和客户端程序都是QT6开发的64位应用程序。服务器为一个独立进程工作在80端口。通过Bash Shell脚本启动了100个客户端进程,每一个进程与服务器建立了1万个连接。最后服务器承接了将近100万个TCP长连接。
每一个客户端建立与服务器的连接之后,每TCP连接每秒约发送一个约20字节的数据包之后开始接收服务器的回应数据,然后不断循环执行这个过程。为了避免占用过多CPU,也为了避免数据收发消耗掉过多内存,每发送一条数据等待1毫秒,而且每次只发送几十字节的数据。
服务器每次收到新的数据包之后,尽力对每一个数据包原封不动的发送到对应的客户端,相当于一个echo服务器。
实测效果
本文描叙实例对应的视频如下:
视频: QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器效果
QT是否适合做高性能网络应用?补天云这个视频告诉你在大厂Linux云服务器上的实测结果:QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器
QT网络模块高性能高并发网络服务器:100万TCP连接截图
QT网络模块高性能高并发网络服务器:80万TCP连接截图
QT网络模块高性能高并发网络服务器:1万TCP连接截图
为了避免在短时间内众多客户端瞬间建立太多TCP连接,在控制脚本和客户端代码中都加了一点延时操作。
实测统计结果表明服务器平均每秒接收和发送了各1MB数据。整体上相当于服务器每秒处理约5万个数据包,在应用层平均每秒接收1000到2000个新的TCP连接。
建立完成100个TCP连接,总耗时2小时30分,其中包括程序的延时和脚本的延时以及各种人工操作时的空闲等待时间。
QT网络模块提供的QTcpServer和QTcpSocket的事件分发机制的底层实现看起来似乎并非最优解。Windows版本使用Windows异步选择(AsyncSelect)消息机制,Linux版本使用Linux 投票(Poll)机制。但是就是这样的底层设计,实测仍然是通过了C1000K测试。
本次测试主要关注了QT网络服务器在Linux系统中是否能支持100万个TCP长连接。截图显示服务器在按照echo模式运行时收发数据包的字节数基本相等。体现了QT网络服务器可以实现一定程度的高并发性能和高性能。
本文作者还另外进行了QT网络服务器的数据吞吐量方面的测试,即使在Windows系统中在1万TCP长连接的情况下服务器也可实现100MB/秒到1GB/秒的吞吐量。体现了QT网络服务器可以实现一定程度的高性能和高吞吐量。
当然,不足之处在于网络延迟不是很好控制。
QT网络模块百万连接高性能高并发服务器应用实例源代码
服务器源代码
服务器主程序:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ButianyunTcpServer server;
server.listen(QHostAddress::AnyIPv4, 80);
qDebug() << QDateTime::currentDateTime().toString() << " Server is Ready.";
QTimer* timer = new QTimer(&a);
timer->setInterval(1000 * 10);
QObject::connect(timer, &QTimer::timeout,
timer, [&server] {
ButianyunTcpServerState stat = server.getServerState();
qDebug() << QDateTime::currentDateTime().toString()
<< " connection count:{" << stat.connection_count << "} "
<< " bytes read:{" << butianyun_bytes_human_readable(stat.bytes_read) << "} "
<< " bytes written:{" << butianyun_bytes_human_readable(stat.bytes_written) <<"} "
<< " error count:{" << stat.error_count << "}";
});
timer->start();
return a.exec();
}
服务器类型定义:
class ButianyunTcpConnection : public QTcpSocket
{
Q_OBJECT
public:
explicit ButianyunTcpConnection(QObject *parent = nullptr);
signals:
void sig_connection_info(long long read_bytes, long long write_bytes, bool error);
private slots:
void slot_connected();
void slot_readyRead();
void slot_bytesWritten(qint64 bytes);
void slot_disconnected();
void slot_errorOccurred(QAbstractSocket::SocketError error);
void slot_aboutToClose();
private:
QList<QByteArray> data_to_write;
QByteArray data_last_write;
};
服务器类型构造函数:
ButianyunTcpConnection::ButianyunTcpConnection(QObject *parent)
: QTcpSocket{parent}
{
connect(this, &ButianyunTcpConnection::connected,
this, &ButianyunTcpConnection::slot_connected);
connect(this, &ButianyunTcpConnection::readyRead,
this, &ButianyunTcpConnection::slot_readyRead);
connect(this, &ButianyunTcpConnection::bytesWritten,
this, &ButianyunTcpConnection::slot_bytesWritten);
connect(this, &ButianyunTcpConnection::disconnected,
this, &ButianyunTcpConnection::slot_disconnected);
connect(this, &ButianyunTcpConnection::errorOccurred,
this, &ButianyunTcpConnection::slot_errorOccurred);
connect(this, &ButianyunTcpConnection::aboutToClose,
this, &ButianyunTcpConnection::slot_aboutToClose);
}
² 客户端源代码
客户端的常数:
//一个客户端向服务器发起1万个连接。
#define BUTIANYUN_CONNECTION_COUNT_PER_CLIENT 10000
#define BUTIANYUN_CONNECTION_COUNT_PER_THREAD 1000
#define BUTIANYUN_THREAD_COUNT 10
#define BUTIANYUN_SOCKET_BUF_SIZE (1024 * 4)
#define BUTIANYUN_DATA_BYTES (10)
客户端主程序:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if (argc > 1)
{
remote_host = argv[1];
}
QThreadPool pool;
pool.setMaxThreadCount(BUTIANYUN_THREAD_COUNT);
for (int i = 0; i < BUTIANYUN_THREAD_COUNT; i++)
{
pool.start(butianyun_network_client);
}
pool.waitForDone();
qDebug() << "all connections exited.";
return a.exec();
}
客户端线程池中的线程函数:
static QAtomicInt connection_count = 0;
static QString remote_host = "127.0.0.1";
static void butianyun_network_client()
{
QThread::msleep(1000);
int connection_count_in_this_thread = 0;
QTcpSocket* clients = new QTcpSocket[BUTIANYUN_CONNECTION_COUNT_PER_THREAD];
for (int i = 0; i < BUTIANYUN_CONNECTION_COUNT_PER_THREAD; i++)
{
QThread::msleep(1);
clients[i].connectToHost(remote_host, 80);
clients[i].waitForConnected();
if (clients[i].state() == QTcpSocket::ConnectedState)
{
connection_count_in_this_thread++;
connection_count++;
}
clients[i].setSocketOption(QTcpSocket::KeepAliveOption, 1);
clients[i].setSocketOption(QTcpSocket::LowDelayOption, 1);
clients[i].setSocketOption(QTcpSocket::SendBufferSizeSocketOption, BUTIANYUN_SOCKET_BUF_SIZE);
clients[i].setSocketOption(QTcpSocket::ReceiveBufferSizeSocketOption, BUTIANYUN_SOCKET_BUF_SIZE);
}
qDebug() << "total " << connection_count << ", "
<< "this " << connection_count_in_this_thread << " connections.";
unsigned long long id = 0;
QByteArray bytes_read;
QString dummy;
dummy.resize(BUTIANYUN_DATA_BYTES);
dummy.fill(QChar('A'), BUTIANYUN_DATA_BYTES);
while (1)
{
long error_count = 0;
for (int i = 0; i < BUTIANYUN_CONNECTION_COUNT_PER_THREAD; i++)
{
id++;
QTcpSocket& client = clients[i];
if (client.state() == QTcpSocket::UnconnectedState)
{
error_count++;
continue;
}
QString msg = QString("%1:BuTianYun QT Network C1000K Test")
.arg(id);
msg += dummy;
client.write(msg.toUtf8());
client.waitForBytesWritten();
client.waitForReadyRead();
QByteArray bytes = client.readAll();
QThread::msleep(1);
}
if (error_count == BUTIANYUN_CONNECTION_COUNT_PER_THREAD)
{
qDebug() << "thread exited.";
break;
}
}
delete []clients;
}
QT网络模块的整体认识
QT网络模块对QT Widgets传统应用程序的支持
QT网络模块对传统QT Widgets应用的支持
QT网络模块对QML应用程序的支持
QT网络模块对QT QML应用的支持
QT网络模块套接字TCP SSL支持
QT对TCP 套接字C/S架构应用的支持
QT网络模块对传统的基于套接字的网络应用程序提供了支持。使用QTcpServer和QTcpSocket类型提供了对基于TCP的客户端服务器架构(C/S架构)的网络应用程序的支持。
QT TCP套接字C/S架构应用
QT对UDP应用的支持
QT网络模块提供了QUdpSocket类型提供了对Udp应用程序的支持。
QT UDP套接字应用
QT对Sctp应用的支持
QT网络模块提供了QSctpServer和QSctpSocket提供了对Sctp应用程序的支持。
QT对SSL应用的支持
QT网络模块提供了QSslServer和QSslSocket类型提供了对SSL套接字应用程序的支持。
QT对本地套接字的支持
QT网络模块提供了QLocalServer和QLocalSocket类型提供了对本地套接字应用程序的支持。
QT网络模块Web HTTP/HTTPS协议支持
QT对Web客户端应用的支持
QT网络模块提供了QNetworkAccessManager 、QNetworkRequest和QNetworkReply提供了对HTTP和HTTPS客户端应用程序的支持,使得我们可以直接使用QT提供的高层网络API编写HTTP/HTTPS客户端应用程序。比如用很少的代码就可以下载Web服务器上的网页数据,包括HTML/JSON/XML数据和二进制数据文件。另外,QT网络模块还提供了QHttpMultiPart类型以此支持 MIME multipart message。
QT对Web客户端应用的支持
QT对WebSocket应用的支持
QT网络模块提供了QWebSocketServer和QWebSocket类型提供对WebSocket服务器应用和WebSocket客户端应用的支持。说白了就是可以直接使用QT编写WebSocket服务器应用程序和WebSocket客户端应用程序,而无需关注WebSocket内部细节。
QT对WebSocket应用的支持
QT网络模块QML+AJAX+WebSocket支持
QT QML对AJAX应用的支持
下图是使用QT QML 提供的XMLHttpRequest对象执行HTTP POST操作的应用实例。
QT QML的XMLHttpRequest对HTTP POST的支持
下图是使用QT QML 提供的XMLHttpRequest对象执行HTTP GET操作的应用实例。
QT QML的XMLHttpRequest对HTTP GET的支持
QT QML对WebSocket应用的支持
QT QML提供了WebSocketServer和WebSocket这两个QML类型,以此支持使用QT QML开发WebSocket服务器应用和WebSocket客户端应用程序。
下图是QT QML开发的WebSocket服务器和WebSocket客户端的应用实例。
QT QML对WebSocket应用的支持
总结
本文介绍了在某大厂云服务器中使用QT网络模块提供的QTcpServer和QTcpSocket类型编写的C/S架构的网络应用成功通过了C1000K测试(即成功建立了100万个TCP长连接并能维持正常通讯)的实测情况和源代码。本文还简略介绍了QT网络模块所包含的各种网络相关功能的支持情况。
如果您认为这篇文章对您有所帮助,请您一定立即点赞+喜欢+收藏,本文作者将能从您的点赞+喜欢+收藏中获取到创作新的好文章的动力。如果您认为作者写的文章还有一些参考价值,您也可以关注这篇文章的作者。
【QT性能优化】QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器:QT是否适合做高性能网络应用?补天云这个视频告诉你在大厂Linux云服务器上的实测结果的更多相关文章
- MarioTCP:一个单机可日30亿的百万并发长连接服务器
原文:http://blog.csdn.net/everlastinging/article/details/10894493 注:如果用此服务器做变长data的传输,请在业务处理函数中为input ...
- 网络编程-socket(三)(TCP长连接和UDP短连接、时间服务器)
详解地址:https://www.cnblogs.com/mys6/p/10587673.html TCP server端 import socketsk = socket.socket() # 创建 ...
- LinkedIn的即时消息:在一台机器上支持几十万条长连接
最近我们介绍了LinkedIn的即时通信,最后提到了分型指标和读回复.为了实现这些功能,我们需要有办法通过长连接来把数据从服务器端推送到手机或网页客户端,而不是许多当代应用所采取的标准的请求-响应模式 ...
- 最快1天搭建短视频APP!阿里云短视频解决方案上线
短视频行业的发展前景乐观是毋庸置疑的,整个短视频的市场规模一直在增长,网络数据显示2018年已经突破100亿大关,在2019年预测将超过200亿.那么,对于短视频从业者来讲,要持续推动业务的发展,必须 ...
- http的长连接和短连接(史上最通俗!)
1.以前的误解 很久之前就听说过长连接的说法,而且还知道HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接.但终究觉得对于长连接一直懵懵懂懂的,有种抓不到关键点的感觉. 今天 ...
- Web服务器性能监控分析与优化
Web服务器性能监控分析与优化 http://www.docin.com/p-759040698.html
- Citrix 服务器虚拟化之十三 Xenserver虚拟机内存优化与性能监控
Citrix 服务器虚拟化之十三 Xenserver虚拟机内存优化与性能监控 XenServer的DMC通过自动调节运行的虚拟机的内存,每个VM分配给指定的最小和最大内存值之间,以保证性能并允许每 ...
- Web性能优化:图片优化
程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...
- Web前端性能优化之图片优化
我自己的Blog:http://blog.cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到了互联网内容总量的62%,也就是说超过 ...
- TVP思享 | 四个全新维度,极限优化HTTP性能
导语 | 当产品的用户量不断翻番时,需求会倒逼着你优化HTTP协议.那么,要想极限优化HTTP性能,应该从哪些维度出发呢?本文将由TVP陶辉老师,为大家分享四个全新维度.「TVP思享」专栏,凝结大咖思 ...
随机推荐
- 领域驱动设计(DDD)分层架构的三种模式
模式一:四层架构 1.User Interface为用户界面层(或表示层),负责向用户显示信息和解释用户命令.这里指的用户可以是另一个计算机系统,不一定是使用用户界面的人.2.Application为 ...
- 如何查询MySQL存储的树形结构,层次结构
表定义如下 如果我们需要在表中查询这个树状结构,通过SQL语句,有两种查询方法: 1.通过inner自连接查询,适用于简单的结构 SELECT * FROM course_category AS on ...
- 12、SpringMVC之拦截器
12.1.环境搭建 创建名为spring_mvc_interceptor的新module,过程参考9.1节和9.5节 12.1.1.页面请求示例 <a th:href="@{/test ...
- 【Java】图片上传逻辑
后台逻辑: 后台服务,用Dubbo框架作为一个文件微服务 package cn.ymcd.aisw.service; import cn.ymcd.aisw.dto.RpcResult; /** * ...
- 【Canal】01 入门 & Kafka模式
什么是Canal (卡耐尔) ? Canal 是用 Java 开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件 原理基于MySQL的binlog从库监听 一.MySQL ...
- 【Java】POI Excel导出 动态行合并
一般情况: Excel导出一般都是一行一行的记录输出 . 这是Controller代码: 标题行的设置: 标题行会设置获取的结果集的字段名,数据会自动根据设置的名称匹配装填 特殊的需求: 如页面的效果 ...
- 【Vue】Vue-Cli 安装
首先需要Node.js环境支持: Node.js官网下载: https://nodejs.org/en/ 右边稳定版,左边最新版 下载安装程序之后双击运行,无脑下一步 打开终端输入版本查看命令: no ...
- 【TypeScript】01 基础入门
前提:使用TypeScript你需要安装NodeJS支持 然后安装TypeScript: npm intsall -g typescript 安装完成后查看版本号: tsc -v 新建一个TypeSc ...
- 进程的CPU绑定是否有意义 —— 进程的 CPU 亲和性
好多年前就学习过 进程的 CPU 亲和性这个概念,说直白些就是CPU的进程绑定,也就是指定某个进程绑定到某个CPU核心上,以此提高进程切换时缓存的命中率,加快进程的运算速度. 虽然在编程的时候中会遇到 ...
- 深入学习JVM-JVM 安全点和安全区域
什么是安全点? 在 JVM 中如何判断对象可以被回收 一文中,我们知道 HotSpot 虚拟机采取的是可达性分析算法.即通过 GC Roots 枚举判定待回收的对象. 那么,首先要找到哪些是 GC R ...