ZeroMQ 断言失败:套接字句柄由于某种原因不再有效

ZeroMQ assertion failed: socket handle no longer valid for some reason

使用 ZeroMQ 获得了一个 Windows 10 c++ 程序,由于断言失败,该程序在同一组计算机上经常中止。

assert 语句深埋在 libzmq 代码中。

在其他机器上,相同的程序运行良好,没有这些问题(但平心而论,那是因为 OS 内部版本号和程序配置不同)。

断言失败似乎是因为内部 zeromq(基于套接字 and/or 管道)连接/句柄意外关闭。

什么可能导致这样的事情?

更多信息:

断言失败似乎与 ZeroMQ 用于内部信号的 channels/mailboxes 有关。在旧版本的库中,这适用于多个环回 TCP 套接字,而现代版本依赖于涉及 IOCP(I/O 完成端口)的解决方案。

这是一个长期存在且可能相关的问题,原作者本人谈到了发生在他身上的类似崩溃:

https://github.com/zeromq/libzmq/issues/1108

使用我们的应用程序的故障转储,我看到通向 assert 语句的堆栈跟踪通常发生在尝试从套接字(或套接字文件描述符?)读取之后的某个时刻。读取或接收操作失败,然后库崩溃。

所以,突然之间套接字句柄似乎不再有效。我看到的错误示例是“资源暂时不可用”和“无效 handle/parameter”之类的内容。

会不会是什么东西或者什么人强行帮我们关闭了socket? 是什么导致了这种行为?

旧版本的 zeromq (4.0.10) 和现代版本 (4.3.5) 都会出现这种情况。这让我相信,如果这些不同的实现以大致相同的方式失败,那么故障出在其他地方。

当尝试重现问题时,我可以通过手动强制关闭 ZeroMQ 与 TCPView 一起使用的内部 TCP 连接来触发 4.0.x 的类似断言失败。由此产生的断言失败是即时的,故障转储看起来与野外发生的情况相同。

但是现代版本似乎没有使用环回套接字,所以我无法关闭那里的“私有”连接。也许他们正在使用管道或 unix 样式的套接字(我听说现在可以在 Windows 10 上实现)。

有一段时间我认为短暂的端口耗尽是造成所有这些麻烦的原因,但仅此一点对我来说没有意义:我不希望 OS 强制关闭现有连接,现有连接应该继续工作。您预计只有新连接会失败。

正如@user253751 所建议的,罪魁祸首似乎是应用程序中的一段特定代码,它关闭了相同的 HANDLE 两次。我们代码中的一个严重错误,而不是 ZeroMQ!

在 Windows 上,关闭的句柄会立即得到重用,因此在第一个 CloseHandle 之后立即打开的任何内容在第二个 CloseHandle 触发时都有被意外关闭的风险,由于错误。