使用连接的套接字终止 QWebSocket服务器



我调试用C++/Qt 5.12.1编写的控制台多线程应用程序。它运行在Linux Mint 18.3 x64上。

此应用程序具有SIGINT处理程序,QWebSocketServerQWebSocket表。它使用close()QWebSocketServer并调用表中QWebSocket项的abort()/deleteLater()来处理终止。

如果 websocket 客户端连接到此控制台应用程序,则由于某些正在运行的线程(我想它是内部QWebSocket线程)而终止失败。 如果没有连接,则终止成功。

如何解决?以便应用正常退出。

要优雅地退出套接字服务器,我们可以尝试:

最重要的部分是允许主线程事件循环运行并等待 QWebSocketServer::closed() 以便插槽调用 QCoreApplication::quit()。

即使通过以下方法也可以做到这一点:

connect(webSocketServer, &QWebSocketServer::closed,
QCoreApplication::instance(), &QCoreApplication::quit);

如果我们不需要更详细的反应。

先连接该信号后,继续执行pauseAccepting()以防止更多连接。 呼叫QWebSocketServer::close.

如果上述内容足够,则可能不需要以下内容。您需要先尝试上述操作,并且只有在仍有问题时才处理现有和挂起的连接。根据我的经验,行为在平台上有所不同,并且在服务器环境中有一些独特的websocket实现(这可能只是Qt)。

只要我们有一些包含QWebSocket实例的数组,我们就可以尝试对所有实例调用QWebSocket::abort()以立即释放。这一步似乎是由问题作者描述的。

尝试使用 QWebSocketServer::nextPendingConnection() 迭代挂起的连接,并为它们调用abort()。调用deleteLater,如果这也有效。

不需要做任何事情。"优雅退出"是什么意思?一旦有终止应用程序的请求,您应该立即使用exit(0)或类似机制终止它。这就是"优雅退出"应该是什么。

注意:我被改革了。我曾经认为优雅的退出是一件好事。它们通常是对 CPU 资源的浪费,并且通常表明应用程序体系结构中存在问题。

为什么它应该写在kj框架(capnproto的一部分)中是一个很好的理由。

引用肯顿·瓦尔达的话:

KJ_NORETURN(virtual void exit()) = 0;

指示程序完成。 该计划被认为是成功的,除非error()叫。 通常,这以_Exit()退出,这意味着堆栈没有展开,缓冲 不刷新等 -- 调用方负责刷新任何缓冲区 事。 但是,替代上下文实现(例如用于单元测试目的)可以 选择改为引发异常。

起初,这种方法可能听起来很疯狂。 干净地关闭不是更好吗? 如果 您丢失了数据? 但是,事实证明,如果您查看每个常见的程序类,_Exit()几乎总是可取的。 让我们分解一下:

  • 命令:您可能从命令行运行的典型程序是单线程的,并且 快速且确定地退出。 命令通常使用缓冲 I/O,需要刷新 退出前的那些缓冲区。 但是,析构函数执行的大多数工作不是 刷新缓冲区,但释放内存,将对象放入自由列表,然后关闭 文件描述符。 如果进程无论如何都要退出,所有这些都无关紧要,并且 对于快速运行的命令,浪费释放堆空间的时间可能会产生真正的影响 在脚本的整体运行时中。 同时,通常很容易确定确切的内容 资源需要在退出前刷新,并且很容易判断它们是否没有被刷新 (因为该命令无法生成预期的输出)。 因此,它是合理的 命令很容易明确确保在退出之前刷新所有输出,并且它是 无论如何,他们这样做可能是个好主意,因为应该检测到写入失败 并处理。 对于命令,一个好的策略是分配任何需要清理的对象 堆栈上的销毁,并允许它们在命令退出之前超出范围。 同时,任何不需要清理的资源都应作为成员分配 命令的主类,其析构函数通常不会被调用。

  • 交互式应用:与用户交互的程序(无论是图形应用) 对于Windows或基于控制台的应用程序(如Emacs)通常仅在用户询问时才退出 自。 此类应用程序可能会在需要同步的内存中存储大型数据结构 到磁盘,例如文档或用户首选项。 但是,依靠堆栈展开或全局 析构函数作为确保此类同步发生的机制可能是错误的。 第一个 总而言之,现在是2013年,应用程序应该主动将更改同步到非易失性。 在进行这些更改的那一刻存储。 应用程序可能随时崩溃和崩溃 切勿丢失超过半秒的数据。 同时,如果用户实际上 确实尝试在存在未保存的更改时关闭应用程序,应用程序 UI 应该 提示用户决定要执行的操作。 这样的 UI 机制显然太高级别了,无法 通过析构函数实现,因此 KJ 对_Exit()的使用在这里应该不会有什么不同。

  • 服务器
  • :一个好的服务器是容错的,为随时的可能性做好准备 它可能会崩溃,操作系统可能会决定杀死它,或者运行它的机器可能会 去死吧。 所以,使用 _Exit() 应该没有问题。 事实上,服务器通常甚至从未 无论如何都要呼叫退出;他们被外部杀死。

  • 批处理作业
  • :长时间运行的批处理作业介于命令和服务器之间。 它 可能确切地知道退出前需要刷新什么,并且可能应该是 容错。

相关内容

  • 没有找到相关文章

最新更新