可以使用 waitForReadyRead() 而不是为 readyRead() 信号创建槽吗?
Is it OK to use `waitForReadyRead()` instead of creating a slot for `readyRead()` signal?
使用 Qt 编写跨平台应用程序(包括 Windows 和 MinGW)。为了从 SSL 套接字读取数据,我创建了一个单独的线程。这个线程是有历史原因的,因为早些时候应用程序是使用 C socket/ssl/crypto 库编写的。现在所有这些都被 Qt 网络库取代了。
对于阻塞线程,waitForReadyRead(milliseconds)
似乎是更好的选择。现在根据 Qt 层次结构:
QIODevice
|
QAbstractSocket
|
QTcpSocket
|
QSslSocket
QAbscractSocket::waitForReadyRead()
的文档建议:
Note: This function may fail randomly on Windows. Consider using the event loop and the readyRead() signal if your software will run on Windows.
但是QIODevice::waitForReadyRead()
中没有提到类似的警告。
问题:QSslSocket::waitForReadyRead()
是否始终适用于所有平台?
为什么我没有使用 readyRead() 信号?
出于某些奇怪的原因,如果我使用 readyRead() 插入某个方法,那么它不会被调用。此外, QSslSocket::write() 也不起作用,否则上述方法会起作用。由于我的代码很复杂,我无法在这里展示它。
根据你的问题。
QIODevice 的实现只做 return false。所以不需要有时会失败的暗示。
QAbstractSocket 的实现在内部调用了一个叫做 "nativeSelect" 的东西,然后它被定向到相应的方法,这取决于你 运行 所在的 OS。对于 Windows,select 实现有时似乎 return 是一个否定的错误。
但这不会对您造成伤害,因为您应该在下次调用 waitForReadyRead() 时获得可用数据的提示。
QSslSocket 的 waitForReadyRead() 内部使用了一些 SSL 检查中的 QAbstactSocket 的实现。
关于信号和槽的问题。
我刚接触 Qt 时犯的一个错误是,我试图在启动 MainLoop 之前通过调用 QApplication::exec() 或其他方式发出信号。
如果没有 运行 循环,信号槽机制将无法工作。
希望你能从中得到一些提示。
此致
虽然这不是 Qn 的确切答案,但我发布了 waitForReadyRead()
的可能实现,它可以在本地事件循环下使用。
class MySslSocket : QSslSocket
{
Q_OBJECT
public:
virtual
bool
waitForReadyRead (int milliseconds) override final
{
QEventLoop eventLoop;
QTimer timer;
connect(this, SIGNAL(readyRead()), &eventLoop, SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
timer.setSingleShot(true);
timer.start(milliseconds);
eventLoop.exec();
return timer.isActive();
}
};
这可以专用于 Windows,也可以通用于所有平台。
关于您的问题:是的,您可以使用 QSslSocket::waitForReadyRead()
,但在 Widows 上,即使数据到达套接字,它也可能超时。因此,如果发生超时,您必须检查它是否超时或方法失败。检查很简单,如果 QAbstractSocket::bytesAvailable() > 0
则数据已准备好读取,否则超时。
当您使用小超时并且您的应用程序对延迟不敏感时(例如,温度传感器与具有温度历史记录的云之间的通信),这种方法是可行的。但是,如果您不能接受任何不必要的延迟,那么您应该使用 signal/slot 界面。
有关详细信息,您可以查看 Qt 错误跟踪器上的 bug report。
问题可能是使用资源。
当你使用 waitForReady*
时,你会为每个线程创建一个套接字约束(否则你会遇到奇怪的错误)。
现在的问题是你有多少个插座?如果它取决于 运行 时间数据,你可能不知道。
某些嵌入式系统对可能影响您的应用程序的线程数有限制,IMO 这只是可能影响此类实现的限制。
你这部分问题:
Why am I not using readyRead() signal? For some strange reason, if I
slot some method with readyRead() then it's not getting called.
Moreover, the QSslSocket::write() also doesn't work, which works
otherwise with above approach. Due to complexity of my code, I am
unable to present it here.
看起来很可疑。
我从未见过有人有类似的问题。也许您的代码的某些部分正在阻止事件循环?
使用 Qt 编写跨平台应用程序(包括 Windows 和 MinGW)。为了从 SSL 套接字读取数据,我创建了一个单独的线程。这个线程是有历史原因的,因为早些时候应用程序是使用 C socket/ssl/crypto 库编写的。现在所有这些都被 Qt 网络库取代了。
对于阻塞线程,waitForReadyRead(milliseconds)
似乎是更好的选择。现在根据 Qt 层次结构:
QIODevice
|
QAbstractSocket
|
QTcpSocket
|
QSslSocket
QAbscractSocket::waitForReadyRead()
的文档建议:
Note: This function may fail randomly on Windows. Consider using the event loop and the readyRead() signal if your software will run on Windows.
但是QIODevice::waitForReadyRead()
中没有提到类似的警告。
问题:QSslSocket::waitForReadyRead()
是否始终适用于所有平台?
为什么我没有使用 readyRead() 信号?
出于某些奇怪的原因,如果我使用 readyRead() 插入某个方法,那么它不会被调用。此外, QSslSocket::write() 也不起作用,否则上述方法会起作用。由于我的代码很复杂,我无法在这里展示它。
根据你的问题。 QIODevice 的实现只做 return false。所以不需要有时会失败的暗示。 QAbstractSocket 的实现在内部调用了一个叫做 "nativeSelect" 的东西,然后它被定向到相应的方法,这取决于你 运行 所在的 OS。对于 Windows,select 实现有时似乎 return 是一个否定的错误。 但这不会对您造成伤害,因为您应该在下次调用 waitForReadyRead() 时获得可用数据的提示。 QSslSocket 的 waitForReadyRead() 内部使用了一些 SSL 检查中的 QAbstactSocket 的实现。
关于信号和槽的问题。 我刚接触 Qt 时犯的一个错误是,我试图在启动 MainLoop 之前通过调用 QApplication::exec() 或其他方式发出信号。 如果没有 运行 循环,信号槽机制将无法工作。
希望你能从中得到一些提示。
此致
虽然这不是 Qn 的确切答案,但我发布了 waitForReadyRead()
的可能实现,它可以在本地事件循环下使用。
class MySslSocket : QSslSocket
{
Q_OBJECT
public:
virtual
bool
waitForReadyRead (int milliseconds) override final
{
QEventLoop eventLoop;
QTimer timer;
connect(this, SIGNAL(readyRead()), &eventLoop, SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
timer.setSingleShot(true);
timer.start(milliseconds);
eventLoop.exec();
return timer.isActive();
}
};
这可以专用于 Windows,也可以通用于所有平台。
关于您的问题:是的,您可以使用 QSslSocket::waitForReadyRead()
,但在 Widows 上,即使数据到达套接字,它也可能超时。因此,如果发生超时,您必须检查它是否超时或方法失败。检查很简单,如果 QAbstractSocket::bytesAvailable() > 0
则数据已准备好读取,否则超时。
当您使用小超时并且您的应用程序对延迟不敏感时(例如,温度传感器与具有温度历史记录的云之间的通信),这种方法是可行的。但是,如果您不能接受任何不必要的延迟,那么您应该使用 signal/slot 界面。
有关详细信息,您可以查看 Qt 错误跟踪器上的 bug report。
问题可能是使用资源。
当你使用 waitForReady*
时,你会为每个线程创建一个套接字约束(否则你会遇到奇怪的错误)。
现在的问题是你有多少个插座?如果它取决于 运行 时间数据,你可能不知道。
某些嵌入式系统对可能影响您的应用程序的线程数有限制,IMO 这只是可能影响此类实现的限制。
你这部分问题:
Why am I not using readyRead() signal? For some strange reason, if I slot some method with readyRead() then it's not getting called. Moreover, the QSslSocket::write() also doesn't work, which works otherwise with above approach. Due to complexity of my code, I am unable to present it here.
看起来很可疑。
我从未见过有人有类似的问题。也许您的代码的某些部分正在阻止事件循环?