You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:54:53