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

QSslServer仅二次请求触发newConnection,waitForEncrypted失败问题

生成包含localhost的自签名证书

使用以下OpenSSL命令生成带subjectAltName(包含localhost)的自签名EC证书:

openssl req -x509 -newkey ec:<(openssl ecparam -name secp384r1) -sha256 -nodes 
  -keyout "$KEY_FILE" -out "$CERTIFICATE_FILE" -days "$DAYS" 
  -subj "/C=GB/ST=England/L=London/O=$COMPANY_NAME/CN=$WEBSITE" 
  -addext "subjectAltName=DNS:$WEBSITE,DNS:localhost" 

其中$KEY_FILE为私钥输出路径,$CERTIFICATE_FILE为证书输出路径,$DAYS为证书有效期,$COMPANY_NAME为组织名称,$WEBSITE为主域名。

Qt6 C++ 最小SSL服务端实现

以下是调用setLocalCertificate、捕获newConnection信号并追踪incomingConnection的Qt6 C++最小服务端代码:

#include <QCoreApplication>
#include <QFile>
#include <QSslCertificate>
#include <QSslKey>
#include <QSslServer>

class Server : public QSslServer
{
public:
    Server(
        const QSslCertificate & certificate,
        const QSslKey& private_key)
    {
        QSslConfiguration config;
        {
            config.setLocalCertificate(certificate);
            config.setPrivateKey(private_key);
            config.setProtocol(QSsl::TlsV1_2OrLater);
        }

        setSslConfiguration(config);

        connect(this, &QSslServer::newConnection, [this]()
        {
            this->new_connection(); // not a slot
        });

        auto digest = certificate.digest(QCryptographicHash::Sha256);
        qDebug() << "Server starting using " << digest.toHex(':') << ", " << (private_key.isNull() ? "NULL KEY" : "KEY OK");
    }

private:
    void incomingConnection(qintptr fd) override
    {
        qDebug() << "incomingConnection(" << fd << ")";
        QSslServer::incomingConnection(fd);
    }
    
    void new_connection()
    {
        while (auto tcp_socket = nextPendingConnection())
        {
            // In full implementation, this will be in another thread,
            // which will use synchronous calls on the socket.
            auto ssl_socket = dynamic_cast<QSslSocket*>(tcp_socket);
            qDebug() << "nextPendingConnection() " << ssl_socket->peerAddress();
            if (!ssl_socket->waitForEncrypted(5000))
                qDebug() << "Handshake failed: "  << ssl_socket->errorString();
            else
            {
                auto data = ssl_socket->readAll();
                qDebug() << "Read " << data.size();
            }
        }
    }
};


int main (int argc, char ** argv)
{
    QCoreApplication app(argc, argv);

    QFile crt_file(argv[1]);
    crt_file.open(QIODevice::ReadOnly);
    QSslCertificate certificate(crt_file.readAll());

    QFile private_key_file(argv[2]);
    private_key_file.open(QIODevice::ReadOnly);
    auto private_key_contents = private_key_file.readAll();
    QSslKey private_key(private_key_contents, QSsl::Ec);

    Server server(certificate, private_key);
    server.listen(QHostAddress::Any, 2000);

    qDebug() << "Listening.";

    return app.exec();
}
测试异常现象

启动服务端后,使用命令openssl s_client -connect localhost:2000 -servername localhost测试,出现以下异常:

  • 首次连接:服务端仅输出 incomingConnection( 7 ),无其他日志;客户端完成SSL握手后挂起。
  • 第二次连接:服务端输出如下日志,触发newConnection但waitForEncrypted调用失败:
incomingConnection( 7 )
nextPendingConnection()  QHostAddress("")
Handshake failed:  "The remote host closed the connection"

内容的提问来源于stack exchange,提问作者spraff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 07:13:14