1. Qt6使用https协议在客户端发送一条文字消息到服务器端。

之前的 HTTP 示例改成 HTTPS,这样客户端通过 TLS 加密发送一条文字消息到服务器端。
这里有几个关键点需要注意:

🔑 关键变化

  1. Qt 客户端

    • 使用 QNetworkAccessManager + QNetworkRequest,但 URL 必须是 https://
    • 需要配置 QSslConfiguration(证书验证、加密套件等)
    • 如果是自签名证书,需要在客户端信任它(开发阶段可以临时忽略验证)
  2. 服务器端

  • Qt 自带的 QTcpServer 不直接支持 HTTPS,需要用 QSslSocketQTcpServer+QSslSocket 组合
  • 必须加载服务器的私钥和证书(PEM 格式)
  • 证书可以用 openssl 自签名生成

1️⃣ 生成自签名证书(开发测试用)

在终端执行:

1
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \  -keyout server.key -out server.crt

然后合并成一个 .pem 文件:

1
cat server.key server.crt > server.pem

2️⃣ HTTPS 服务器(Qt6)

httpsserver.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef HTTPSSERVER_H
#define HTTPSSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QSslSocket>
#include <QSslCertificate>
#include <QSslKey>

class HttpsServer : public QObject
{
Q_OBJECT
public:
explicit HttpsServer(QObject *parent = nullptr);

private slots:
void onNewConnection();
void onEncrypted();
void onReadyRead();

private:
QTcpServer server;
QSslCertificate certificate;
QSslKey privateKey;
};

#endif // HTTPSSERVER_H

httpsserver.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "httpsserver.h"
#include <QFile>
#include <QDebug>

HttpsServer::HttpsServer(QObject *parent) : QObject(parent)
{
QFile certFile("server.pem");
if (!certFile.open(QIODevice::ReadOnly)) {
qWarning() << "Cannot open certificate file";
return;
}
certificate = QSslCertificate(&certFile, QSsl::Pem);
certFile.seek(0);
privateKey = QSslKey(&certFile, QSsl::Rsa, QSsl::Pem);

if (!server.listen(QHostAddress::Any, 8443)) {
qWarning() << "Failed to start HTTPS server";
return;
}
qDebug() << "HTTPS Server listening on port 8443";

connect(&server, &QTcpServer::newConnection,
this, &HttpsServer::onNewConnection);
}

void HttpsServer::onNewConnection()
{
QTcpSocket *tcpSocket = server.nextPendingConnection();
QSslSocket *sslSocket = new QSslSocket(this);

sslSocket->setSocketDescriptor(tcpSocket->socketDescriptor());
sslSocket->setLocalCertificate(certificate);
sslSocket->setPrivateKey(privateKey);
sslSocket->setProtocol(QSsl::TlsV1_2OrLater);

connect(sslSocket, &QSslSocket::encrypted,
this, &HttpsServer::onEncrypted);
connect(sslSocket, &QSslSocket::readyRead,
this, &HttpsServer::onReadyRead);

sslSocket->startServerEncryption();
tcpSocket->deleteLater();
}

void HttpsServer::onEncrypted()
{
qDebug() << "SSL handshake completed";
}

void HttpsServer::onReadyRead()
{
QSslSocket *socket = qobject_cast<QSslSocket*>(sender());
if (!socket) return;

QByteArray request = socket->readAll();
qDebug().noquote() << request;

int idx = request.indexOf("\r\n\r\n");
QByteArray body;
if (idx != -1) {
body = request.mid(idx + 4).trimmed();
}

qDebug() << "Received:" << QString::fromUtf8(body);

QByteArray responseBody = "Server received: " + body;
QByteArray response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: " + QByteArray::number(responseBody.size()) + "\r\n"
"\r\n" + responseBody;

socket->write(response);
socket->disconnectFromHost();
}

3️⃣ HTTPS 客户端(Qt6)

httpsclient.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef HTTPSCLIENT_H
#define HTTPSCLIENT_H

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>

class HttpsClient : public QObject
{
Q_OBJECT
public:
explicit HttpsClient(QObject *parent = nullptr);
void sendMessage(const QUrl &url, const QString &message);

private slots:
void onFinished(QNetworkReply *reply);
void onSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);

private:
QNetworkAccessManager manager;
};

#endif // HTTPSCLIENT_H

httpsclient.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "httpsclient.h"
#include <QDebug>
#include <QNetworkRequest>
#include <QSslConfiguration>

HttpsClient::HttpsClient(QObject *parent) : QObject(parent)
{
connect(&manager, &QNetworkAccessManager::finished,
this, &HttpsClient::onFinished);

connect(&manager, &QNetworkAccessManager::sslErrors,
this, &HttpsClient::onSslErrors);
}

void HttpsClient::sendMessage(const QUrl &url, const QString &message)
{
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");

// 开发阶段忽略自签名证书错误(生产环境不要这样做)
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);

manager.post(request, message.toUtf8());
}

void HttpsClient::onFinished(QNetworkReply *reply)
{
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
QByteArray body = reply->readAll();

qDebug() << "HTTP Status:" << statusCode << reason;
qDebug() << "Response body:" << QString::fromUtf8(body);

reply->deleteLater();
}

void HttpsClient::onSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
qWarning() << "SSL Errors:" << errors;
reply->ignoreSslErrors(); // 仅开发阶段使用
}

4️⃣ main.cpp

服务端

1
2
3
4
5
6
7
8
9
#include <QCoreApplication>
#include "httpsserver.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
HttpsServer server;
return a.exec();
}

客户端

1
2
3
4
5
6
7
8
9
10
#include <QCoreApplication>
#include "httpsclient.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
HttpsClient client;
client.sendMessage(QUrl("https://127.0.0.1:8443"), "Hello over HTTPS!");
return a.exec();
}

运行说明

  1. 先运行 服务端(会监听 8443 端口)
  2. 再运行 客户端(会通过 HTTPS 发送消息)
  3. 服务端会打印收到的消息,客户端会显示状态码和响应内容