zmq-cpp:recv() 等待数据,尽管设置了ZMQ_DONTWAIT

zmq-cpp: recv() waits for data despite ZMQ_DONTWAIT being set

本文关键字:设置 ZMQ DONTWAIT recv 数据 等待 zmq-cpp      更新时间:2023-10-16

我正在尝试使用 ZMQ_DONTWAIT 标志使用 ZeroMQ 实现非阻塞接收方法,但recv()行为就像在没有标志的情况下被调用一样:

    auto start = std::chrono::steady_clock::now();
    auto have_data = sock_->recv(&reply, ZMQ_DONTWAIT);
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
                std::chrono::steady_clock::now() - start).count();
    std::cout << duration << " " << have_data;

sock_是实例化为REQ套接字的zmq::socket_t

在这种情况下,have_data始终为真,durationREP服务器回复所需的任何内容(0 到几百毫秒(。

请注意,我说的是 zmq.hpp 中定义的 ZeroMQ 的 cpp 绑定,其中recv()的声明与 zmq.h 中的声明不同:

inline bool recv (message_t *msg_, int flags_ = 0);

在这里,recv()返回true是否已收到数据,false errno是否EAGAIN

ZMQ_DONTWAIT立即返回recv()是否有任何先决条件?

(我使用的是zmq版本4.1.2(

是的。(ZeroMQ应考虑先决条件。

一个小提示:ZeroMQ 允许人们设置具有ZMQ_RCVTIMEO == 0或性能合理值的setsockopt()

然而,主要问题隐藏在REQ/REP行为模式中。

如果应用程序在REQ ">跳">到状态[*]并在那里等待任何可能已经到达[REQ]-<Rx>缓冲区的内容(在此用例中原则上是不可能的(,或者可能会在稍后的某个时间到达,但REP 交易对手没有任何要回复的,未经REQ事先.recv()请求,不得也不会.send()任何内容。

    ]-<Tx>- - - - - - - - - +                      + - - - - - - - -<Tx>-[
    ]-<Rx>- - - - - - - -+  |                      :  +- - - - - - -<Rx>-[
[REQ]____________________:__|                      :__|__________________[REP]
                         :  |                      :  |
APP.send() ]--->.send()--:->|                      :  |
           ]             |  :                     :  |
           ]             |  : ____________________:__|>
           ]             |  :                      :  |M
           .             .  .                      .  .M
           ?             ?  ?                      ?  ?
           .             .  .                      .  .M
           ]             |  :                      :  |M_.recv()--->[ APP.recv()
           ]             |  :                      |  :             [ and
           .             .  .                      .  .             [ can 
           ?             ?  ?                      ?  ?             ?
           .             .  .                      .  .             [ 
           ]             |  :                      |  :             [    .send()
           ]             |  :                      |  :             [ after
           ]             |  :                      |  :             [    .recv()
           ]             |  :                      |  :             [ 
           ]             |  :                      |<-:--.send()<---[ APP.send()
           ]             |  :                     /:  |
           ]            <|__:____________________/ :  |
           ]            M|  :                      :  |
           .            M.  .                      .  .
           ?             ?  ?                      ?  ?
           .            M.  .                      .  .
[*]        ]            M|  :                      :  |
APP.recv() ]<---.recv()_M|  :                      :  |
                         :  |                      :  |

你可以看看名为 czmq 的高级 ZeroMQ API。它带有ZeroMQ库。它有函数 zstr_recv_nowait(( 详细信息: zstr 手册页

例:

//some code
void *listener = zsocket_new (ctx, ZMQ_SUB); //zctx_t *ctx
//...
while (!zctx_interrupted)
{
     char* message = zstr_recv_nowait(listener);
     if (message && message[0]!='') {
      //do some work
     }
}