可以使用 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.

看起来很可疑。
我从未见过有人有类似的问题。也许您的代码的某些部分正在阻止事件循环?