QTcpServer运行多日后突然停止接受新连接,报WSAEINVAL错误
QTcpServer运行2-3天后停止接受连接,WSAAccept返回WSAEINVAL错误
原本正常运行的QTcpServer在持续监听2-3天后突然停止接受新连接(关联的qBittorrent WebUI同步失效)。排查Qt源码发现,监听套接字调用WSAAccept时返回WSAEINVAL错误——但该套接字此前已正常运行三天,不符合MSDN文档中“无效级别参数”或“对非监听套接字调用accept”的典型触发场景。
最小复现示例(MRE)
server.h
#include <QTcpServer> namespace Http { class Server final : public QTcpServer { Q_OBJECT Q_DISABLE_COPY_MOVE(Server) public: explicit Server(QObject *parent = nullptr); private: void incomingConnection(qintptr socketDescriptor) override; }; }
server.cpp
#include "server.h" #include <QTcpSocket> using namespace Http; Server::Server(QObject *parent) : QTcpServer(parent) {} void Server::incomingConnection(const qintptr socketDescriptor) { QTcpSocket *serverSocket = nullptr; serverSocket = new QTcpSocket(this); serverSocket->setSocketDescriptor(socketDescriptor); QByteArray x = "HTTP/1.1 400 Bad Request\r\nServer: Boost.Beast/353\r\nContent-Type: text/html\r\nContent-Length: 19\r\n\r\nUnknown HTTP-method"; serverSocket->write(x); serverSocket->waitForBytesWritten(); serverSocket->disconnectFromHost(); serverSocket->waitForDisconnected(); serverSocket->deleteLater(); }
main.cpp
int main(int argc, char* argv[]) { QCoreApplication a(argc, argv); auto server = Http::Server(nullptr); server.listen(QHostAddress::Any, 50001); return QCoreApplication::exec(); }
解决方案
1. 替换阻塞式API为异步信号槽处理
你的incomingConnection实现中使用了waitForBytesWritten()、waitForDisconnected()这类阻塞函数,会持续占用QTcpServer所在线程的事件循环。长时间运行后,事件循环积压可能导致套接字内部状态异常,最终触发WSAEINVAL错误。修改为异步处理:
void Server::incomingConnection(const qintptr socketDescriptor) { QTcpSocket *serverSocket = new QTcpSocket(this); // 绑定信号槽异步处理流程 connect(serverSocket, &QTcpSocket::bytesWritten, this, [serverSocket]() { serverSocket->disconnectFromHost(); }); connect(serverSocket, &QTcpSocket::disconnected, serverSocket, &QTcpSocket::deleteLater); connect(serverSocket, &QAbstractSocket::errorOccurred, serverSocket, [serverSocket](QAbstractSocket::SocketError) { serverSocket->deleteLater(); }); // 设置套接字描述符,失败则直接释放资源 if (!serverSocket->setSocketDescriptor(socketDescriptor)) { delete serverSocket; return; } // 发送响应 QByteArray response = "HTTP/1.1 400 Bad Request\r\nServer: Boost.Beast/353\r\nContent-Type: text/html\r\nContent-Length: 19\r\n\r\nUnknown HTTP-method"; serverSocket->write(response); }
2. 定期检查监听状态并自动恢复
添加定时任务周期性检查QTcpServer状态,若监听意外中断则自动重启:
Server::Server(QObject *parent) : QTcpServer(parent) { QTimer* checkTimer = new QTimer(this); connect(checkTimer, &QTimer::timeout, this, [this]() { if (!this->isListening()) { qWarning() << "Server stopped listening, restarting..."; this->listen(QHostAddress::Any, 50001); } }); checkTimer->start(30000); // 每30秒检查一次 }
3. 排查系统级资源问题
长时间运行后出现套接字错误,可能是Windows系统套接字资源耗尽:
- 查看系统
TCP连接数和套接字句柄数是否达到上限 - 确保客户端套接字通过
deleteLater()被正确释放(异步处理能更可靠地保证这一点)
4. 升级Qt版本
部分旧版本Qt的网络模块在Windows下存在长时间运行后的状态异常bug,升级到最新LTS版本(如Qt 5.15.x或Qt 6.x)可能解决该问题。
内容的提问来源于stack exchange,提问作者isudfv
相关产品推荐
相关产品推荐

