3

I want to check the existence ( state ) of a server before I send a ZeroMQ request, but I have no idea how to do it.

user3666197
  • 1
  • 6
  • 50
  • 92
Yacheng Zhou
  • 53
  • 1
  • 4
  • Send "hello request" or simply ping server. However high level networking protocols may guarantee or not successful packet delivery (e.g. TCP does and UDP not). – f4f Oct 30 '19 at 08:28
  • 1
    @f4f You may know ZeroMQ already has a smart low-level heartbeat **detection "inside" the RFC:ZMTP wire-level** (hidden) **protocol specification**. Adding L3/4-level test so as to detect but a **Line-of-Sight visibility-test** does **not** seem to solve to problem of detecting an **app-level Live-or-Dead Agent-test**, so this let me in serious doubts about whether to ever implement something in a direction your have proposed the O/P to proceed. **What are, in your view, the advantages of paying any costs for receiving nothing "useful" to rely on?** Did I miss anything? – user3666197 Oct 31 '19 at 12:37
  • You are right in notice that app-level and network-level visibility are totally different. But I have no idea about distributed system design used by topic starter so just mentioned that variety of possible solutions varies a lot (in order to hear some additional requirements or limitations from him). Sending data with no awareness whether it is received may be useful too. For example it's used for some low-level sensors and connected devices (when data stream is constant and additional logic on sender's side costs to much). ZMQ PUB/SUB model designed somewhat that way. – f4f Oct 31 '19 at 13:29

2 Answers2

1

Q : I want to check the existence ( state ) of a server before I send a ZeroMQ request

The solution is to setup and use the services of a zmq_socket_monitor()

// Read one event off the monitor socket; return value and address
// by reference, if not null, and event number by value. Returns -1
// in case of error.

static int
get_monitor_event ( void  *monitor,
                    int   *value,
                    char **address
                    )
{   
    zmq_msg_t msg;
    zmq_msg_init ( &msg );                                       // First frame in message contains event number and value
    if ( zmq_msg_recv ( &msg, monitor, 0 ) == -1 ) return -1;    // Interrupted, presumably
    assert ( zmq_msg_more ( &msg )              & "REASON: Frame #1 FAILED TO SIG 2nd, EXPECTED, FRAME TO COME" );

    uint8_t  *data  =  ( uint8_t  * ) zmq_msg_data ( &msg );
    uint16_t  event = *( uint16_t * ) ( data );

    if ( value )
        *value = *( uint32_t * ) ( data + 2 );


    zmq_msg_init ( &msg );                                      // Second frame in message contains event address
    if ( zmq_msg_recv ( &msg, monitor, 0 ) == -1 ) return -1;   // Interrupted, presumably
    assert ( !zmq_msg_more ( &msg )             & "REASON: Frame #2 FAILED TO SIG more, NOT EXPECTED, FRAMEs TO COME" );

    if ( address ) {
        uint8_t *data = ( uint8_t * ) zmq_msg_data ( &msg );
        size_t   size =               zmq_msg_size ( &msg );
        *address = ( char * ) malloc ( size + 1 );
        memcpy ( *address, data, size );
        ( *address )[size] = 0;
    }
    return event;
}

int main ( void )
{   
    void    *ctx = zmq_ctx_new ();
    assert ( ctx                                & "REASON: Context FAILED to instantiate" );

    void    *client = zmq_socket ( ctx, ZMQ_DEALER );
    assert ( client                             & "REASON: Socket FAILED to instantiate" );

 // Socket monitoring only works over inproc://
    int      rc = zmq_socket_monitor ( client, "inproc://monitor-client-side", ZMQ_EVENT_ALL );
    assert ( rc == 0                            & "REASON: socket_monitor FAILED to instantiate over INPROC:// transport-class" );

 // Create socket for collecting monitor events
    void    *client_side_mon = zmq_socket ( ctx, ZMQ_PAIR );
    assert ( client_side_mon                    & "REASON: socket_monitor receiving Socket FAILED to instantiate " );

 // Connect these to the inproc endpoints so they'll get events
             rc = zmq_connect ( client_side_mon, "inproc://monitor-client-side" );
    assert ( rc == 0                            & "REASON: .connect()-method FAILED to get connected" );

 // Now do whatever you need
    ...

 // Close client
    close_zero_linger ( client );

 // --------------------------------------------------------------------
 // How to collect and check events from socket_monitor:
    int  event =  get_monitor_event ( client_side_mon, NULL, NULL );

    if ( event == ZMQ_EVENT_CONNECT_DELAYED )
         event =  get_monitor_event ( client_side_mon, NULL, NULL );

    assert ( event == ZMQ_EVENT_CONNECTED       & "REASON: [client]-socket still not in an expected, .connect()-ed, state" );
    ...

    ...
    event = get_monitor_event ( client_side_mon, NULL, NULL );
    assert ( event == ZMQ_EVENT_MONITOR_STOPPED & "REASON: [client]-socket not in an expected, .close()-ed, state" );

 // --------------------------------------------------------------------
 // FINALLY:
 // --------------------------------------------------------------------
 // Close down the sockets
    close_zero_linger ( client_side_mon );

    zmq_ctx_term ( ctx );

    return 0;
    }

( included in API since v3.2+ )

user3666197
  • 1
  • 6
  • 50
  • 92
  • I tried use get_monitor_event to monitor the REQ client in a thread,and do it in a while loop,but It seems to cause other requests to current process will be blocked. – Yacheng Zhou Oct 30 '19 at 13:26
  • Never use a blocking-mode call anywhere "***outside*" a school-book example** – user3666197 Oct 30 '19 at 15:06
  • Hi, Thanks for the info, but is this also doable in Python? – Cypher Feb 07 '23 at 15:04
  • Oh sure it is @Cypher If your current pyzmq bindings do not explicitly mention any interface towards the native socket-monitor tools, kindly re-read the native ZeroMQ API documentation ( call-signature details to look for ) and then re-check your actual / updated pyzmq source-code ( as it still might have the socket-monitor tools present, just not presented in documentation ). Finally if not present there, one may extend the source-code and match the ZeroMQ native API specifications to have socket-monitor tools still available. Good luck - worth making a try, – user3666197 May 16 '23 at 21:48
0

You are best off setting up a full connection and devising a simple ACK protocol between the client and server before the sockets is considered to be working normally. If the client receives the ACK within a reasonable time the server is up. Otherwise the server is down, and the client is best closing the socket and trying again until it succeeds.

N.B. If the socket isn't closed, the messages can build up in the ZMQ send queue and risk flooding the server with lots of ACK messages when the server does finally connect.

John Jefferies
  • 1,176
  • 7
  • 13
  • Are you sure to call this a **best practice**? ZeroMQ already has a smart low-level heartbeat **detection "inside" the RFC:ZMTP wire-level** (hidden) **protocol specification**. Adding app-level complexity so as to achieve an already served task does not seem to adjust the costs ( and side-effects ) of doing so, so this let me in serious doubts about whether to ever implement something in a direction your have proposed the O/P to proceed. **What are, in your view, the advantages of paying more than twice the costs for receiving nothing more, than you already have?** Did I miss anything? – user3666197 Oct 31 '19 at 12:32
  • AIUI the low level heart-beating in ZMTP isn't directly available to clients, but is used to return connect & disconnect events to the socket monitor. I still maintain it's simpler to devise your own protocol to determine if a socket is alive after an attempt to connect it. – John Jefferies Nov 01 '19 at 16:47