【问题标题】:ZMQ: "Resource temporarily unavailable" when connecting zmq socketZMQ:连接zmq套接字时“资源暂时不可用”
【发布时间】:2018-01-15 03:02:25
【问题描述】:

我正在尝试通过 czmqz (4.0.2) 使用 libzmq (4.2.2) 在 Python 程序和我的 C++ 应用程序之间建立 IPC 通信通道。

我正在使用 ZMQ 发布者/订阅者模式,其中 Python 程序绑定到端口并使用 pyzmq (16.0.2) 发布消息,而我的 C++ 程序使用来自 CZMQ 的 zsock class 作为订阅者进行连接。

问题是,每当我的订阅者尝试连接时,我都会返回错误代码 11,资源暂时不可用。奇怪的是,这个系统似乎在我的开发机器上工作得很好,但在我要部署到的目标系统上却不行。

问题出现在以下简略方法初始化套接字的第一行:

bool ZmqSocketWrapper::connectSubscriber(string address)
{
    m_address = address;
    m_pSocket = zsock_new_sub(address.c_str(), "");

    int errorCode = zmq_errno();
    if (errorCode != 0)
    {
        printf(zmq_strerror(errorCode));
        return false;
    }

    return true;
}

这样调用:

m_subscriberSocket->connectSubscriber("tcp://127.0.0.1:5555");

我还尝试了其他变体,结果相同:

m_subscriberSocket->connectSubscriber("tcp://localhost:23232");
m_subscriberSocket->connectSubscriber("ipc:///tmp/test");

在线搜索时,似乎大多数其他人在尝试发送/接收时都会遇到这个问题,所以我在尝试打开套接字时遇到这个问题似乎很奇怪。

其他一些细节:

  • 我的 ZMQ 发布器是使用 pyzmq 用 Python 编写的,并且在同一目标系统上运行良好,这表明问题出在 czmq 中。
  • 我发现问题的机器是 Raspberry Pi,以防万一,但请记住以上几点。
  • 不,没有其他任何东西在使用该端口,并且我已使用 netstat 确认服务器端口正在侦听。
  • 是的,我已尝试以 root 身份运行我的客户端。

非常感谢任何帮助!

【问题讨论】:

  • 我建议您在 strace 中运行您的应用程序,看看那里到底发生了什么故障。它可能会给你一些提示。
  • 谢谢@SergeyA。我尝试在 Python 程序和 C++ 程序上都使用strace -e trace=network,并让它们都做同样的事情(只需将套接字绑定到 tcp://*:5555)。 strace 输出的唯一区别是分配的文件描述符 ID。在 C++ 中我总是得到socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 27,而在Python中我总是得到socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 10
  • 在这两种情况下,以下strace 行是setsockopt(10, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0; bind(10, {sa_family=AF_INET, sin_port=htons(6666), sin_addr=inet_addr("0.0.0.0")}, 16) = 0; listen(10, 100) = 0; getsockname(10, {sa_family=AF_INET, sin_port=htons(6666), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0;

标签: python c++ sockets ipc zeromq


【解决方案1】:

好消息是纯pyzmq 场景运行良好,

硬件或操作系统相关问题似乎已从故障列表中排除。


该死的绑定 (通过“高级”倾斜抽象使用户程序失明)

第一件事是,
一些高级工业家提倡摆脱原生 API 删除用户端选项。

CZMQ 这样做是因为它假设 每个SUB 方都希望只选择.connect(),而不是让相反的.bind()/.connect() 选项可用.旧好的 ZeroMQ API 总是让用户使用这个选项,这是公平的。同样,在设置套接字连接之前需要设置许多性能调整变量,这使得“高级”绑定对于分布式系统实现更加麻烦。

接下来是奇怪的事情,代码在一个盒子上运行良好,而在另一个盒子上却没有。

我担心在zmq.Context()之前将LINGER设置为零+.close()任何此类创建的SUB套接字(如果没有适当的异常处理,则不必发生)在zmq.Context()之前由用户负责实例是安全的.term()-inated。这可能会挂起后来导致实际资源被(仍然)占用的孤儿,从而导致errno 代码 11,Resource temporarily unavailable.

最后但并非最不重要 - 资源不是消耗品/一次性用品

建议的代码不能更好地展示这种资源效率低下的行为,并且每次调用都会累积所有设置/配置/拆卸开销成本。这是一个非常糟糕的设计实践(虽然用户可能会在许多“教科书”示例中遇到它)。如果对高效分布式计算参数的更多细节感兴趣,也与此相关,may also like this post.

bool ZmqSocketWrapper::connectSubscriber(string address)
{   b_RetFLAG = true;
    m_address = address;
    m_pSocket = zsock_new_sub(address.c_str(), "");

    int errorCode = zmq_errno();
    if (errorCode != 0)
    {
        printf(zmq_strerror(errorCode));
        b_RetFLAG = false;
    }
 // -------------------------------------------------------------
    zsock_destroy( &m_pSocket ); // USER's MANDATORY DUTY PRE-RET
 // -------------------------------------------------------------
    return b_RetFLAG;
}

如果确实遇到了麻烦,

使用本地 API,您的代码完全控制舞台。

【讨论】:

  • 非常感谢您的回复。请放心,在我的代码的其他部分,我会断开(如果已连接)并销毁(如果已创建)我的套接字!我现在使用m_pSocket = zsock_new(ZMQ_SUB); 创建套接字,然后使用zsock_connect(m_pSocket, "%s", address.c_str()); 连接它,但这会导致与以前相同的错误。我还在连接之前尝试了zsock_set_linger(m_pSocket, 500);。这似乎没有做任何事情,当我在这个调用之后检查错误代码时,我得到错误代码 22: Invalid argument.
  • ZeroMQ API 3.x 是否也是如此?
  • 我还没有尝试过,在我看来使用最新的会是明智的,特别是因为我也在使用 pyzmq。您认为我尝试降级到较旧的 zmq 和 czmq 是否值得?如果有,为什么?
  • 好吧,重点不是让您重新安装,而是决定运行 A/B 测试的 B 部分以 { revoke |确认}-问题,一旦不使用 CZMQ,而是通过本机 API 调用执行相同的场景 - 开始并保留从第一个 zmq_context() 到最后一个 zmq_term() 的完全控制。仍然依赖于 CZMQ 包装的流程,许多细节超出了您的控制/诊断范围。为什么要提到 3.x >>> api.zeromq.org/3-2:_start ?最近的 4.x+ 开始触及不可触碰的原则(共享套接字,这可能在更新语言绑定等方面引起新问题)
  • 是的 - 我现在正在使用本机 ZMQ 调用,并且不再看到问题。我最好的猜测是,我在检查 C 绑定函数调用时遇到了误报。
猜你喜欢
  • 2018-11-26
  • 2014-03-16
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-26
相关资源
最近更新 更多