可以从QsslServer::sslErrors调用QDialog::exec吗?

3
我正在开发一个使用SSL套接字进行通信的应用程序。当一个不受信任的客户端连接到服务器时,它会发出sslError。现在我需要向用户询问决定,使用QDialog::exec(我不能使用异步操作,因为我需要在sslError中处理错误,要么忽略sslError,要么中止连接,这取决于用户的决定)。此外,当我打开另一个窗口时,客户端断开连接(客户端套接字似乎被删除),然后当我访问套接字时,QDialog exec返回时会抛出内存访问冲突的错误。
Qt文档中对QDialog::exec的说明如下:

注意:避免使用此函数;而是使用open()。与exec()不同,open()是异步的,并且不会启动额外的事件循环。这可以防止发生一系列危险的错误(例如,在通过exec()打开对话框时删除对话框的父对象)。当使用open()时,您可以连接到QDialog的finished()信号,以便在对话框关闭时得到通知。

在这种情况下我应该怎么办?

我有一个备选的身份验证流程,它从连接开始,如果有任何sslHandshakeErrors,允许连接继续,然后稍后我会异步显示对话框,如果用户按下确定,我发送一个名为authOk的数据包并继续读取,否则我发送一个名为authFailed的数据包并断开客户端连接。但在这个过程中,似乎没有使用标准的SSL连接握手。

是否有更好的解决方案,谢谢:)


有什么建议吗? - undefined
抱歉,我打错了赏金信息,实际上应该是“我需要一个好的解决方案来在sslErrors信号中对ssl客户端进行身份验证”。谢谢 :) - undefined
3个回答

1
一个更好的解决方案可能是异步地接受ssl错误:
- 如果用户尚未批准错误,请拒绝连接。 - 异步地询问用户是否要忽略此类错误。当相同的ssl错误再次发生时,使用用户的决定。
即使Qt支持同步方法,同步地请求用户同意往往会导致连接超时,因为用户可能无法及时响应。
以下是一个基本的代码示例(在实际情况中,您应该检查报告的错误):
bool acceptErrors = false; // some global state to keep track of the errors the user allowed to ignore.

const auto processSslErrors = [=] (QSslSocket * sock, const QList<QSslError> & errors){    
  if (acceptErrors) // check if the user wants to ignore this error
    sock->ignoreSslErrors();
  else {
    // reject the connection for now, but ask the user if he wants to ignore this error in the future
    QTimer::singleShot(0, [](){
      auto dialog = QMessageBox(QMessageBox::Critical, "SSL Error", "Accept ?", QMessageBox::Yes | QMessageBox::Cancel);
  
      // show the dialog
      dialog.exec();
  
      // if user accepted
      if (dialog.result() == QMessageBox::Yes) {
        acceptErrors = true; 
      }
    });
  }
};

0
这是一个架构问题。
每个线程都可以有一个事件循环,但小部件只能存在于主线程中。
QDialog::exec创建一个模态对话框,它会停止主线程之外的大部分事件处理,但不会停止其他线程。
你需要一个事件循环来处理信号。
你需要一个正在运行的事件循环来异步处理数据。
你需要有一个或两个额外的线程,这样你就可以拥有独立的事件循环:
主线程 - 用户界面线程(UI)
管理线程(MT) - 一个状态机,跟踪应用程序的状态(可选)
通信线程(CT) - 会话或套接字所在的位置
MT的状态机可以在通信中实现,但请确保在需要时使用queued connection
这样,你完全解开了每一边可能发生的各种状态。用户的操作会被传递给MT,MT会决定如何处理CT的状态并通知UI当前的进展。CT处理数据的处理,当结果准备好时,会向MT或UI发出信号。
作为一个附带的好处,你将拥有一个符合单一职责原则和可能符合开闭原则的结构。你只需要修改UI来改变它对用户操作或状态变化的反应,即"输入"。你只需要修改CT来改变协议。
请注意,只有没有父对象的对象才能移动到另一个线程,否则`moveToThread`将会静默失败。为了简化UI的工作,你可能需要一种建造者模式,即将一个对象移动到线程中,然后由该对象创建其他对象。

谢谢你的回答。如果可能的话,你能提供一个示例程序吗? - undefined

-2
似乎你正在处理一个情况,需要在Qt应用程序的握手过程中处理SSL错误,并与用户进行交互以基于这些错误做出决策。在这种情况下使用QDialog::exec()是有问题的,因为它会阻塞事件循环,而你希望避免阻塞事件循环以防止像你描述的那样的问题。
我的建议是为身份验证对话框使用一个单独的线程。

谢谢你的回答,看起来我无法将小部件从主线程移动到另一个线程 :( 如果可能的话,你能给出任何示例代码吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接