我正在用 Qt 编写 TCP 服务器,它将为大文件提供服务。应用逻辑如下:
- 我将 QTcpServer 子类化并重新实现了incomingConnection(int)
- 在incomingConnection 中,我正在创建“Streamer”类的实例
- “Streamer”正在使用 QTcpSocket,它使用来自incomingConnection 的 setSocketDescriptor 初始化
- 当来自客户端的数据到达时,我从 readyRead() 插槽中发回初始响应,然后将套接字的信号 bytesWritten(qint64) 连接到 Streamer 的插槽 bytesWritten()
bytesWritten 看起来像:
Streamer.h:
...
private:
QFile *m_file;
char m_readBuffer[64 * 1024];
QTcpSocket *m_socket;
...
Streamer.cpp
...
void Streamer::bytesWritten() {
if (m_socket->bytesToWrite() <= 0) {
const int bytesRead = m_file->read(m_readBuffer, 64 * 1024);
m_socket->write(m_readBuffer, bytesRead);
}
}
...
所以基本上我只在所有待处理数据都完全写入时才写入新数据。我认为这是最异步的方式。
一切正常,除了当有很多同时客户端时它会很慢。
大约有 5 个客户端 - 我从该服务器下载,速度约为 1 MB/s(我的家庭互联网连接的最大值)
拥有大约 140 个客户端 - 下载速度约为 100-200 KB/s。
服务器的互联网连接速度为 10 Gbps,有 140 个客户端,它的使用速度约为 100 Mbps,所以我认为这不是问题。
服务器的内存使用量与 140 个客户端 - 100 MB 的 2GB 可用
服务器的 CPU 使用率 - 最高 20%
我使用的是 800 端口。
当端口 800 上有 140 个客户端并且通过它的下载速度为 100-200 KB/s 时,我在端口 801 上运行了单独的副本,并且以 1 MB/s 的速度下载没有问题。
我的猜测是,不知何故,Qt 的事件调度(或套接字通知器?)太慢而无法处理所有这些事件。
我试过了:
- 使用 -O3 编译整个 Qt 和我的应用程序
- 安装libglib2.0-dev并重新编译Qt(因为QCoreApplication使用的是QEventDispatcherGlib或者QEventDispatcherUNIX,所以想看看有什么不同)
- 使用 streamer->moveToThread() 生成几个线程并在incomingConnection(int) 中取决于当前在特定线程中的客户端数量 - 这没有做出任何改变(尽管我观察到速度变化更大)
- 使用生成工作进程
代码:
main.cpp:
#include <sched.h>
int startWorker(void *argv) {
int argc = 1;
QCoreApplication a(argc, (char **)argv);
Worker worker;
worker.Start();
return a.exec();
}
in main():
...
long stack[16 * 1024];
clone(startWorker, (char *)stack + sizeof(stack) - 64, CLONE_FILES, (void *)argv);
然后在主进程中启动 QLocalServer 并将 socketDescriptors 从incomingConnection(int socketDescriptor) 传递给工作进程。它工作正常,但下载速度仍然很慢。
也试过:
- incomingConnection() 中的 fork()-ing 过程 - 这几乎杀死了服务器:)
- 为每个客户端创建单独的线程 - 速度降至 50-100 KB/s
- 将 QThreadPool 与 QRunnable 一起使用 - 没有区别
我正在使用 Qt 4.8.1
我没有主意了。
是与 Qt 相关还是与服务器配置有关?
或者也许我应该使用不同的语言/框架/服务器?我需要为文件提供服务的 TCP 服务器,但我还需要在数据包之间执行一些特定任务,所以我需要自己实现那部分。