是否可以使用`waitForReadyRead()`而不是为`readyRead()`信号创建一个插槽?

时间:2017-06-14 12:21:45

标签: c++ qt ssl blocking qt-signals

使用Qt编写跨平台应用程序(包括带MinGW的Windows)。为了从SSL套接字读取数据,我正在创建一个单独的线程。这个帖子是出于历史原因,因为之前的应用程序是使用C socket / ssl / crypto库编写的。现在所有这些都被Qt网络库取代。

对于阻止线程,waitForReadyRead(milliseconds)似乎是更好的选择。现在根据Qt层次结构:

QIODevice
   |
QAbstractSocket
   |
QTcpSocket
   |
QSslSocket

QAbscractSocket::waitForReadyRead()的文档建议:

  

注意:此功能可能在Windows上随机失败。如果您的软件将在Windows上运行,请考虑使用事件循环和readyRead()信号。

但是QIODevice::waitForReadyRead()中没有提到类似的警告。

问题QSslSocket::waitForReadyRead()是否始终可用于所有平台?

为什么我没有使用readyRead()信号?
由于一些奇怪的原因,如果我用readyRead()插入一些方法,那么它就不会被调用。而且,QSslSocket :: write()也不起作用,否则与上述方法一起工作。由于我的代码很复杂,我无法在此处提供。

4 个答案:

答案 0 :(得分:5)

对于您的问题:是的,您可以使用QSslSocket::waitForReadyRead()但是在Widows上,即使数据进入套接字,它也可以超时。因此,如果发生超时,您必须检查它是否超时或方法失败。如果QAbstractSocket::bytesAvailable() > 0然后数据准备好读取,则检查很简单,否则它会超时。

当您使用小超时并且您的应用程序对延迟不敏感时(例如温度传感器和具有温度历史记录的云之间的通信),这种方法是可行的。但是如果您不接受任何不必要的延迟,那么您应该使用信号/插槽接口。

有关详细信息,请查看Qt错误跟踪器上的bug report

答案 1 :(得分:1)

根据你的问题。 QIODevice的实现只会返回false。因此,没有必要提示有时会失败。 QAbstractSocket的实现在内部调用称为“nativeSelect”的东西,然后根据您运行的操作系统将其定向到相应的方法。对于Windows,select实现有时似乎返回负false。 但这不应该伤害你,因为你应该从下次调用waitForReadyRead()获得可用数据的提示。 QSslSocket的waitForReadyRead()internaly使用QAbstactSocket的一些SSL检查实现appart。

关于信号和插槽的问题。 我刚接触Qt时犯的错误是,在我通过调用QApplication :: exec()或其他东西启动MainLoop之前,我试图发出信号。 没有运行循环,信号插槽机制不起作用。

希望你能从中获得一些提示。

此致

答案 2 :(得分:1)

问题可能是使用资源。

当您使用waitForReady*时,每个线程创建约束一个套接字(否则您将遇到奇怪的错误)。 现在问题是你有多少个插座?如果它取决于运行时数据,您可能不知道。 一些嵌入式系统对可能影响您的应用程序的踏板数量有限制,IMO这只是可能影响此类实施的限制。

这部分问题:

  

为什么我不使用readyRead()信号?出于一些奇怪的原因,如果我   使用readyRead()插入一些方法,然后它就不会被调用。   而且,QSslSocket :: write()也不起作用,这是有效的   否则采用上述方法。由于我的代码很复杂,我是   无法在这里展示。

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

答案 3 :(得分:0)

虽然这不是Qn的确切答案,但我发布了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(); } }; 的可能实现,可以在本地事件循环中使用。

$this->Model->saveAll(array_of_30000_rows);

这可以专门用于Windows,也可以用于所有平台。