QDtls Class
该类为 UDP 套接字提供加密功能。更多内容...
| 头文件: | #include <QDtls> |
| CMake: | find_package(Qt6 REQUIRED COMPONENTS Network) target_link_libraries(mytarget PRIVATE Qt6::Network) |
| qmake: | QT += network |
| 继承自: | QObject |
- 所有成员列表,包括继承的成员
- QDtls 属于网络编程 API 的一部分。
公共类型
| GeneratorParameters | |
| enum | HandshakeState { HandshakeNotStarted, HandshakeInProgress, PeerVerificationFailed, HandshakeComplete } |
公共函数
| QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr) | |
| virtual | ~QDtls() |
| bool | abortHandshake(QUdpSocket *socket) |
| QDtls::GeneratorParameters | cookieGeneratorParameters() const |
| QByteArray | decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) |
| bool | doHandshake(QUdpSocket *socket, const QByteArray &dgram = {}) |
| QSslConfiguration | dtlsConfiguration() const |
| QDtlsError | dtlsError() const |
| QString | dtlsErrorString() const |
| bool | handleTimeout(QUdpSocket *socket) |
| QDtls::HandshakeState | handshakeState() const |
| void | ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) |
| bool | isConnectionEncrypted() const |
| quint16 | mtuHint() const |
| QHostAddress | peerAddress() const |
| quint16 | peerPort() const |
| QList<QSslError> | peerVerificationErrors() const |
| QString | peerVerificationName() const |
| bool | resumeHandshake(QUdpSocket *socket) |
| QSslCipher | sessionCipher() const |
| QSsl::SslProtocol | sessionProtocol() const |
| bool | setCookieGeneratorParameters(const QDtls::GeneratorParameters ¶ms) |
| bool | setDtlsConfiguration(const QSslConfiguration &configuration) |
| void | setMtuHint(quint16 mtuHint) |
| bool | setPeer(const QHostAddress &address, quint16 port, const QString &verificationName = {}) |
| bool | setPeerVerificationName(const QString &name) |
| bool | shutdown(QUdpSocket *socket) |
| QSslSocket::SslMode | sslMode() const |
| qint64 | writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) |
信号
| void | handshakeTimeout() |
| void | pskRequired(QSslPreSharedKeyAuthenticator *authenticator) |
相关的非成员
| enum class | QDtlsError { NoError, InvalidInputParameters, InvalidOperation, UnderlyingSocketError, RemoteClosedConnectionError, …, TlsNonFatalError } |
详细说明
QDtls 类可用于通过用户数据报协议(UDP)与网络对等方建立安全连接。在本质上无连接的 UDP 上建立 DTLS 连接意味着,两个对等方必须首先通过调用doHandshake() 成功完成 TLS 握手。 握手完成后,可使用writeDatagramEncrypted() 向对等方发送加密数据报。来自对等方的加密数据报可通过decryptDatagram() 进行解密。
QDtls 设计为与QUdpSocket 配合使用。由于QUdpSocket 可以接收来自不同对等方的数据报,因此应用程序必须实现解复用,将来自不同对等方的数据报转发至其对应的 QDtls 实例。 可通过网络对等方的地址和端口号建立其与 QDtls 对象之间的关联。在开始握手之前,应用程序必须使用setPeer() 设置对等方的地址和端口号。
QDtls不会从QUdpSocket 读取数据报,这应由应用程序完成,例如在连接到QUdpSocket::readyRead()信号的槽中。随后,这些数据报必须由QDtls进行处理。
注意:QDtls 不会获取QUdpSocket 对象的所有权。
通常,在握手阶段,双方对等体将收发多个数据报。在读取数据报后,服务器和客户端必须将这些数据报传递给 `doHandshake()`,直到发现错误或 `handshakeState()` 返回 `HandshakeComplete` 为止:
// A client initiates a handshake:
QUdpSocket clientSocket;
QDtls clientDtls;
clientDtls.setPeer(address, port, peerName);
clientDtls.doHandshake(&clientSocket);
// A server accepting an incoming connection; address, port, clientHello are
// read by QUdpSocket::readDatagram():
QByteArray clientHello(serverSocket.pendingDatagramSize(), Qt::Uninitialized);
QHostAddress address;
quin16 port = {};
serverSocket.readDatagram(clientHello.data(), clientHello.size(), &address, &port);
QDtls serverDtls;
serverDtls.setPeer(address, port);
serverDtls.doHandshake(&serverSocket, clientHello);
// Handshake completion, both for server and client:
void DtlsConnection::continueHandshake(const QByteArray &datagram)
{
if (dtls.doHandshake(&udpSocket, datagram)) {
// Check handshake status:
if (dtls.handshakeStatus() == QDlts::HandshakeComplete) {
// Secure DTLS connection is now established.
}
} else {
// Error handling.
}
}对于服务器而言,首次调用doHandshake() 时,需提供一个包含 ClientHello 消息的非空数据报。如果服务器还部署了QDtlsClientVerifier ,则首个 ClientHello 消息应为经QDtlsClientVerifier 验证过的消息。
如果在握手过程中无法验证对等方的身份,应用程序必须检查peerVerificationErrors() 返回的错误,然后通过调用ignoreVerificationErrors() 忽略错误,或者通过调用abortHandshake() 终止握手。如果忽略了错误,可以通过调用resumeHandshake() 恢复握手。
握手完成后,即可与网络对等方安全地发送和接收数据报:
// Sending an encrypted datagram:
dtlsConnection.writeDatagramEncrypted(&clientSocket, "Hello DTLS server!");
// Decryption:
QByteArray encryptedMessage(dgramSize);
socket.readDatagram(encryptedMessage.data(), dgramSize);
const QByteArray plainText = dtlsConnection.decryptDatagram(&socket, encryptedMessage);可通过调用shutdown() 关闭 DTLS 连接。
DtlsClient::~DtlsClient()
{
clientDtls.shutdown(&clientSocket);
}警告: 如果您计划稍后重用同一端口号连接到服务器,建议在 销毁客户端的 QDtls 对象之前调用shutdown()。否则,服务器可能会丢弃传入的 ClientHello 消息,更多详细信息和实现提示请参见RFC 6347 第 4.2.8 节。
如果服务器不使用 `QDtlsClientVerifier`,则必须配置其 QDtls 对象以禁用 cookie 验证流程:
auto config = QSslConfiguration::defaultDtlsConfiguration();
config.setDtlsCookieVerificationEnabled(false);
// Some other customization ...
dtlsConnection.setDtlsConfiguration(config);使用非默认生成器参数进行cookie验证的服务器,必须在开始握手之前为其QDtls对象设置相同的参数。
注意: DTLS 协议将路径最大传输单元 (PMTU) 的发现交由应用程序处理。 应用程序可通过setMtuHint() 向 QDtls 提供 MTU 值。此提示仅影响握手阶段,因为只有握手消息可由 DTLS 进行分片和重组。应用程序发送的所有其他消息必须能容纳于单个数据报中。
注意:DTLS 特有的 报头会为应用程序数据增加一些开销,从而进一步缩小了可能的消息大小。
警告: 配置为使用 HelloVerifyRequest 进行响应的服务器 将丢弃所有被分片的 ClientHello 消息,从而永远不会启动握手过程。
DTLS 服务器和DTLS 客户端示例演示了如何在应用程序中使用 QDtls。
另请参阅 QUdpSocket 、QDtlsClientVerifier 、HandshakeState 、QDtlsError 以及QSslConfiguration 。
成员类型文档
[alias] QDtls::GeneratorParameters
enum QDtls::HandshakeState
描述 DTLS 握手当前的状态。
此枚举描述了QDtls 连接的DTLS握手当前状态。
| 常量 | 值 | 描述 |
|---|---|---|
QDtls::HandshakeNotStarted | 0 | 尚未执行任何操作。 |
QDtls::HandshakeInProgress | 1 | 已启动握手,且迄今未发现任何错误。 |
QDtls::PeerVerificationFailed | 2 | 无法确定对等方的身份。 |
QDtls::HandshakeComplete | 3 | 握手已成功完成,并建立了加密连接。 |
另请参阅 QDtls::doHandshake() 和QDtls::handshakeState()。
成员函数文档
[explicit] QDtls::QDtls(QSslSocket::SslMode mode, QObject *parent = nullptr)
创建一个 QDtls 对象,将parent 传递给QObject 构造函数。mode 对于服务器端 DTLS 连接为QSslSocket::SslServerMode ,对于客户端则为QSslSocket::SslClientMode 。
另请参阅 sslMode() 和QSslSocket::SslMode 。
[virtual noexcept] QDtls::~QDtls()
销毁QDtls 对象。
bool QDtls::abortHandshake(QUdpSocket *socket)
中止正在进行的握手。如果socket 上正在进行握手,则返回true;否则,设置相应的错误并返回false。
另请参阅 doHandshake() 和resumeHandshake()。
QDtls::GeneratorParameters QDtls::cookieGeneratorParameters() const
返回当前的哈希算法和密钥,可能是默认值,也可能是之前通过调用setCookieGeneratorParameters() 设置的。
如果 Qt 在配置时支持该算法,则默认哈希算法为QCryptographicHash::Sha256 ;否则为QCryptographicHash::Sha1 。默认密钥来自后端特有的、具有密码学强度的伪随机数生成器。
另请参阅 QDtlsClientVerifier 和setCookieGeneratorParameters()。
QByteArray QDtls::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram)
对dgram 进行解密,并将内容作为明文返回。必须先完成握手过程,才能对数据报进行解密。根据TLS消息的类型,连接可能会向socket 写入数据,该指针必须是有效的。
bool QDtls::doHandshake(QUdpSocket *socket, const QByteArray &dgram = {})
启动或继续 DTLS 握手。socket 必须是一个有效的指针。在启动服务器端 DTLS 握手时,dgram 必须包含从QUdpSocket 读取的初始 ClientHello 消息。如果未发现错误,该函数返回true 。可使用handshakeState() 检测握手状态。若返回false ,则表示发生了一些错误,请使用dtlsError() 获取更详细的信息。
注意:如果 无法确认对等方的身份,错误状态将设置为QDtlsError::PeerVerificationError 。若要忽略验证错误并继续连接,必须先调用ignoreVerificationErrors(),然后调用resumeHandshake()。如果无法忽略这些错误,则必须调用abortHandshake()。
if (!dtls.doHandshake(&socket, dgram)) {
if (dtls.dtlsError() == QDtlsError::PeerVerificationError)
dtls.abortAfterError(&socket);
}另请参阅 handshakeState()、dtlsError()、ignoreVerificationErrors()、resumeHandshake() 以及abortHandshake()。
QSslConfiguration QDtls::dtlsConfiguration() const
返回默认的 DTLS 配置,或通过先前对setDtlsConfiguration() 的调用所设置的配置。
另请参阅 setDtlsConfiguration() 和QSslConfiguration::defaultDtlsConfiguration()。
QDtlsError QDtls::dtlsError() const
返回连接遇到的最后一个错误,或QDtlsError::NoError 。
另请参阅 dtlsErrorString() 和QDtlsError 。
QString QDtls::dtlsErrorString() const
返回连接遇到的最后一个错误的文本描述,或返回空字符串。
另请参阅 dtlsError()。
bool QDtls::handleTimeout(QUdpSocket *socket)
如果在握手过程中发生超时,则会发出handshakeTimeout() 信号。应用程序必须调用 handleTimeout() 来重传握手消息;如果发生超时,handleTimeout() 返回true ,否则返回 false。socket 必须是一个有效的指针。
另请参阅 handshakeTimeout()。
QDtls::HandshakeState QDtls::handshakeState() const
返回此QDtls 的当前握手状态。
另请参阅 doHandshake() 和QDtls::HandshakeState 。
[signal] void QDtls::handshakeTimeout()
数据包丢失可能会导致握手阶段出现超时。在这种情况下,QDtls 会发出一个handshakeTimeout()信号。调用handleTimeout()来重传握手消息:
DtlsClient::DtlsClient()
{
// Some initialization code here ...
connect(&clientDtls, &QDtls::handshakeTimeout, this, &DtlsClient::handleTimeout);
}
void DtlsClient::handleTimeout()
{
clientDtls.handleTimeout(&clientSocket);
}另请参阅 handleTimeout()。
void QDtls::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore)
此方法指示QDtls 仅忽略errorsToIgnore 中列出的错误。
例如,如果您想连接到使用自签名证书的服务器,请参考以下代码片段:
QList<QSslCertificate> cert = QSslCertificate::fromPath("server-certificate.pem"_L1);
QSslError error(QSslError::SelfSignedCertificate, cert.at(0));
QList<QSslError> expectedSslErrors;
expectedSslErrors.append(error);
QDtls dtls;
dtls.ignoreVerificationErrors(expectedSslErrors);
dtls.doHandshake(udpSocket);您还可以在doHandshake() 遇到QDtlsError::PeerVerificationError 错误后调用此函数,然后通过调用resumeHandshake() 继续握手过程。
后续对该函数的调用将覆盖之前调用中传递的错误列表。您可以通过向该函数传递一个空列表来清除需要忽略的错误列表。
另请参阅 doHandshake()、resumeHandshake() 和QSslError 。
bool QDtls::isConnectionEncrypted() const
如果 DTLS 握手成功完成,则返回true 。
另请参阅 doHandshake() 和handshakeState()。
quint16 QDtls::mtuHint() const
返回先前由setMtuHint() 设置的值。默认值为 0。
另请参阅 setMtuHint()。
QHostAddress QDtls::peerAddress() const
返回由setPeer()或QHostAddress::Null 设置的对等方地址。
另请参阅 setPeer()。
quint16 QDtls::peerPort() const
返回对等方的端口号(由setPeer()设置)或0。
另请参阅 setPeer()。
QList<QSslError> QDtls::peerVerificationErrors() const
返回在确定对等方身份时发现的错误。
如果希望在出现错误的情况下仍继续建立连接,必须调用ignoreVerificationErrors()。
QString QDtls::peerVerificationName() const
返回由setPeer() 或setPeerVerificationName() 设置的主机名。默认值为空字符串。
另请参阅 setPeerVerificationName() 和setPeer()。
[signal] void QDtls::pskRequired(QSslPreSharedKeyAuthenticator *authenticator)
QDtls 在协商 PSK 密码套件时会发出此信号,因此随后需要进行 PSK 身份验证。
使用PSK时,客户端必须向服务器发送有效的身份信息和有效的预共享密钥,以便TLS握手继续进行。应用程序可以通过连接到该信号的插槽提供此信息,根据需要填充传入的authenticator 对象。
注意:忽略 此信号,或未能提供所需的凭据,将导致握手失败,从而导致连接被中止。
注意: authenticator 对象由QDtls 拥有,应用程序不得将其删除。
另请参阅 QSslPreSharedKeyAuthenticator 。
bool QDtls::resumeHandshake(QUdpSocket *socket)
如果在握手过程中忽略了对等方验证错误,resumeHandshake() 会恢复并完成握手,并返回true 。socket 必须是一个有效的指针。如果无法恢复握手,则返回false 。
另请参阅 doHandshake()、abortHandshake()、peerVerificationErrors() 和ignoreVerificationErrors()。
QSslCipher QDtls::sessionCipher() const
返回此连接所使用的加密算法cipher ,如果连接未加密,则返回空加密算法。会话的加密算法在握手阶段选定。该加密算法用于对数据进行加密和解密。
QSslConfiguration 提供了一组函数,用于设置加密套件的有序列表,握手阶段将最终从该列表中选择会话加密套件。该有序列表必须在握手阶段开始之前就已准备就绪。
另请参见 QSslConfiguration 、setDtlsConfiguration() 和dtlsConfiguration()。
QSsl::SslProtocol QDtls::sessionProtocol() const
返回此连接所使用的 DTLS 协议版本;如果连接尚未加密,则返回 UnknownProtocol。连接所使用的协议是在握手阶段选定的。
setDtlsConfiguration() 可在握手开始前设置首选版本。
另请参阅 setDtlsConfiguration()、QSslConfiguration 、QSslConfiguration::defaultDtlsConfiguration() 以及QSslConfiguration::setProtocol()。
bool QDtls::setCookieGeneratorParameters(const QDtls::GeneratorParameters ¶ms)
设置来自params 的加密哈希算法和密钥。此函数仅适用于服务器端的QDtls 连接。成功时返回true 。
注意: 必须在握手开始前调用此 函数。
另请参阅 cookieGeneratorParameters()、doHandshake()、QDtlsClientVerifier 以及QDtlsClientVerifier::cookieGeneratorParameters()。
bool QDtls::setDtlsConfiguration(const QSslConfiguration &configuration)
根据configuration 设置连接的TLS配置,成功时返回true 。
注意: 必须在握手开始之前调用此 函数。
另请参阅 dtlsConfiguration() 和doHandshake()。
void QDtls::setMtuHint(quint16 mtuHint)
mtuHint 是最大传输单元(MTU),由应用程序自动检测或推测得出。应用程序无需设置此值。
另请参阅 mtuHint() 和QAbstractSocket::PathMtuSocketOption 。
bool QDtls::setPeer(const QHostAddress &address, quint16 port, const QString &verificationName = {})
设置对等方的地址、port 以及主机名,若操作成功则返回true 。address 不能为空、多播地址或广播地址。verificationName 是用于证书验证的主机名。
另请参阅 peerAddress()、peerPort() 和peerVerificationName()。
bool QDtls::setPeerVerificationName(const QString &name)
设置用于证书验证的主机名name ,若操作成功则返回true 。
注意: 必须在握手开始之前调用此 函数。
另请参阅 peerVerificationName() 和setPeer()。
bool QDtls::shutdown(QUdpSocket *socket)
发送一条加密的关机警报消息,并关闭 DTLS 连接。握手状态变为“QDtls::HandshakeNotStarted ”。socket 必须是一个有效的指针。该函数成功时返回true 。
另请参阅 doHandshake()。
QSslSocket::SslMode QDtls::sslMode() const
对于服务器端连接,返回QSslSocket::SslServerMode ;对于客户端连接,返回QSslSocket::SslClientMode 。
另请参阅 QDtls() 和QSslSocket::SslMode 。
qint64 QDtls::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram)
对dgram 进行加密,并将加密后的数据写入socket 。返回写入的字节数;若发生错误,则返回 -1。在写入加密数据之前,必须完成握手过程。socket 必须是一个有效的指针。
另请参阅 doHandshake()、handshakeState()、isConnectionEncrypted() 和dtlsError()。
相关的非成员函数
enum class QDtlsError
描述了QDtls 和QDtlsClientVerifier 可能检测到的错误。
此枚举描述了QDtlsClientVerifier 和QDtls 类对象可能遇到的通用错误和TLS特定错误。
| 常量 | 值 | 描述 |
|---|---|---|
QDtls::QDtlsError::NoError | 0 | 未发生错误,上一次操作成功。 |
QDtls::QDtlsError::InvalidInputParameters | 1 | 调用者提供的输入参数无效。 |
QDtls::QDtlsError::InvalidOperation | 2 | 在不允许执行该操作的状态下尝试执行了该操作。 |
QDtls::QDtlsError::UnderlyingSocketError | 3 | QUdpSocket::writeDatagram() 失败,QUdpSocket::error() 和QUdpSocket::errorString() 可以提供更具体的信息。 |
QDtls::QDtlsError::RemoteClosedConnectionError | 4 | 已收到 TLS 关闭警报消息。 |
QDtls::QDtlsError::PeerVerificationError | 5 | 在 TLS 握手期间无法验证对等方的身份。 |
QDtls::QDtlsError::TlsInitializationError | 6 | 在初始化底层 TLS 后端时发生错误。 |
QDtls::QDtlsError::TlsFatalError | 7 | TLS 握手期间发生了致命错误,但不是对等方验证错误或 TLS 初始化错误。 |
QDtls::QDtlsError::TlsNonFatalError | 8 | 数据报加密或解密失败,非致命错误,这意味着QDtls 可在该错误发生后继续运行。 |
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.