Search code examples
socketszeromqinproc

How do I cleanly shutdown zeromq DEALER/ROUTER inproc connections


In one of my applications I'm using DEALER/ROUTER inproc connections. I set the linger option on the DEALER socket to 0, so that all messages sent on the DEALER socket shall be discarded once the ROUTER socket is closed. Although this works well for TCP connections, it blocks for inproc. Here's a minimal working example:

#include <zmq.h>

#include <windows.h>

int main()
{
    void *context = zmq_ctx_new();

    void *router = zmq_socket(context, ZMQ_ROUTER);
    zmq_bind(router, "inproc://socket");

    void *dealer = zmq_socket(context, ZMQ_DEALER);
    zmq_connect(dealer, "inproc://socket");

    int linger = 0;
    zmq_setsockopt(dealer, ZMQ_LINGER, &linger, sizeof(linger));

    zmq_close(router);

    // sleep for 1 ms
    Sleep(1);

    // this call blocks
    zmq_send(dealer, "message", 7, 0);

    zmq_close(dealer);
    zmq_ctx_destroy(context);

    return 0;
}

Before the DEALER socket can be closed, the zmq_send() call blocks. In this minimal example, I had to add a Sleep(1) call. When this call is omitted, zmq_send() doesn't block. When blocked, the call stack is as follows:

[External Code] 
libzmq.dll!zmq::signaler_t::wait(int timeout_) Line 253 C++
libzmq.dll!zmq::mailbox_t::recv(zmq::command_t * cmd_, int timeout_) Line 80    C++
libzmq.dll!zmq::socket_base_t::process_commands(int timeout_, bool throttle_) Line 1023 C++
libzmq.dll!zmq::socket_base_t::send(zmq::msg_t * msg_, int flags_) Line 869 C++
libzmq.dll!s_sendmsg(zmq::socket_base_t * s_, zmq_msg_t * msg_, int flags_) Line 346    C++
libzmq.dll!zmq_send(void * s_, const void * buf_, unsigned __int64 len_, int flags_) Line 371   C++

I'm using Windows 10 x64, libzmq 4.2.1 (tested it with 4.1.6 as well), and Visual Studio 2015. How can I cleanly shut down the DEALER/ROUTER connection? Is this a bug in libzmq?


Solution

  • Would it be feasable to use ZMQ_DONTWAIT in your

    zmq_send()

    call and evaluate the errorcode?

    Changing your code to

    // this call blocks no more
    zmq_send(dealer, "message", 7, ZMQ_DONTWAIT);
    int ec = zmq_errno();
    printf("code: %d\nstring: %s\n", ec, zmq_strerror(ec));
    

    would result in

    code: 11

    string: Resource temporarily unavailable

    Alternatively, can a socket monitor be used to detect the close event and prevent further sending? This does depend on your architecture.