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云服务器上的实测结果的更多相关文章

  1. MarioTCP:一个单机可日30亿的百万并发长连接服务器

    原文:http://blog.csdn.net/everlastinging/article/details/10894493 注:如果用此服务器做变长data的传输,请在业务处理函数中为input ...

  2. 网络编程-socket(三)(TCP长连接和UDP短连接、时间服务器)

    详解地址:https://www.cnblogs.com/mys6/p/10587673.html TCP server端 import socketsk = socket.socket() # 创建 ...

  3. LinkedIn的即时消息:在一台机器上支持几十万条长连接

    最近我们介绍了LinkedIn的即时通信,最后提到了分型指标和读回复.为了实现这些功能,我们需要有办法通过长连接来把数据从服务器端推送到手机或网页客户端,而不是许多当代应用所采取的标准的请求-响应模式 ...

  4. 最快1天搭建短视频APP!阿里云短视频解决方案上线

    短视频行业的发展前景乐观是毋庸置疑的,整个短视频的市场规模一直在增长,网络数据显示2018年已经突破100亿大关,在2019年预测将超过200亿.那么,对于短视频从业者来讲,要持续推动业务的发展,必须 ...

  5. http的长连接和短连接(史上最通俗!)

    1.以前的误解 很久之前就听说过长连接的说法,而且还知道HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接.但终究觉得对于长连接一直懵懵懂懂的,有种抓不到关键点的感觉. 今天 ...

  6. Web服务器性能监控分析与优化

    Web服务器性能监控分析与优化 http://www.docin.com/p-759040698.html

  7. Citrix 服务器虚拟化之十三 Xenserver虚拟机内存优化与性能监控

    Citrix 服务器虚拟化之十三   Xenserver虚拟机内存优化与性能监控 XenServer的DMC通过自动调节运行的虚拟机的内存,每个VM分配给指定的最小和最大内存值之间,以保证性能并允许每 ...

  8. Web性能优化:图片优化

    程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...

  9. Web前端性能优化之图片优化

    我自己的Blog:http://blog.cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到了互联网内容总量的62%,也就是说超过 ...

  10. TVP思享 | 四个全新维度,极限优化HTTP性能

    导语 | 当产品的用户量不断翻番时,需求会倒逼着你优化HTTP协议.那么,要想极限优化HTTP性能,应该从哪些维度出发呢?本文将由TVP陶辉老师,为大家分享四个全新维度.「TVP思享」专栏,凝结大咖思 ...

随机推荐

  1. iOS开发基础142-广告归因

    IDFA IDFA是苹果为iOS设备提供的一个唯一标识符,专门用于广告跟踪和相关的营销用途.与之对应的,在Android平台的是谷歌广告ID(Google Advertising ID). IDFA的 ...

  2. emojiCTF2024

    emojiCTF2024 WEB http 题目:​​ 思路: 修改 UA 头为 EMOJI_CTF_User_Agent_v1.0:User-Agent: EMOJI_CTF_User_Agent_ ...

  3. 【Linux】快速文件交互 lrzsz

    首先需要安装依赖: yum install -y lrzsz 没有此依赖,Linux提示找不到命令: [root@localhost ~]# rz -bash: rz: 未找到命令 [root@loc ...

  4. 【Spring Data JPA】09 多表关系 Part2 多对多关系操作

    环境搭建: 用户类: package cn.echo42.domain; import javax.persistence.*; import java.util.HashSet; import ja ...

  5. 中国2023年GDP增速5.2%

    在中美贸易战和三年全球疫情的大背景下,我国的经济依旧保持强有力的增速,这表明了经济发展不断转好,一切恢复到疫情和贸易战之前也是有待期望的.

  6. 一个好主板对CPU超频的现实意义————一次超频经历 (z390ws华硕工作站主板+i7-9700k CPU ,Ubuntu18.04.5系统,8核心超频 5.2Ghz以上,单核心满负荷运转可以稳定运行10多分钟后才重启)

    本人于今年2020年1月份在某宝上购买了一款workstation主板,也就是工作站主板,传说中的华硕Z390WS主板(购入价格为3900元),由于当时手里有些小钱,又弄了一个大蝴蝶1350w的电源( ...

  7. 【转载】网络协议之:sctp流控制传输协议

    原文地址: https://www.cnblogs.com/flydean/p/16277006.html ============================================== ...

  8. git 如何删除一个文件名为nul的文件

    前提 当我发现存在一个nul的文件,手动删除/移动它,都会提示ms-dos功能无效或文件过大.想一想这个nul应该是某个保留字,所以普通的方式不能删除 解决方案 https://stackoverfl ...

  9. Chrome(Google) 浏览器安装Vue2、Vue3插件方法 (亲测有效)

    1.背景 2.步骤 步骤一:下载插件 网站:https://chrome.zzzmh.cn/#/search 百度网盘下载: 链接:https://pan.baidu.com/s/1xdEK-7qVx ...

  10. H5页面\PC端实现QQ客服功能

    1.背景 很多应用都有在线客服,最简单是实现就是利用人们常用的QQ 2.实现 步骤一:授权QQ通讯组件(普通QQ都是可以的) 授权链接:https://shang.qq.com/v3/widget.h ...