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
相关产品推荐
相关产品推荐

