mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-28 07:58:14 +08:00
feadf6d40f
Solution: add API and ZMQ_EVENT_PIPES_STATS event which generates 2 values, one for the egress and one for the ingress pipes respectively. Refactor the events code to be able to send multiple values.
388 lines
14 KiB
Plaintext
388 lines
14 KiB
Plaintext
zmq_socket_monitor_versioned(3)
|
|
===============================
|
|
|
|
|
|
NAME
|
|
----
|
|
|
|
zmq_socket_monitor_versioned - monitor socket events
|
|
|
|
|
|
SYNOPSIS
|
|
--------
|
|
*int zmq_socket_monitor_versioned (void '*socket', char '*endpoint', uint64_t 'events', int 'event_version');*
|
|
|
|
*int zmq_socket_monitor_pipes_stats (void '*socket');*
|
|
|
|
|
|
DESCRIPTION
|
|
-----------
|
|
The _zmq_socket_monitor_versioned()_ method lets an application thread track
|
|
socket events (like connects) on a ZeroMQ socket. Each call to this
|
|
method creates a 'ZMQ_PAIR' socket and binds that to the specified
|
|
inproc:// 'endpoint'. To collect the socket events, you must create
|
|
your own 'ZMQ_PAIR' socket, and connect that to the endpoint.
|
|
|
|
The 'events' argument is a bitmask of the socket events you wish to
|
|
monitor, see 'Supported events' below. To monitor all events for a version, use
|
|
the event value ZMQ_EVENT_ALL_V<version>, e.g. ZMQ_EVENT_ALL_V1. For non-DRAFT event
|
|
versions, this value will not change in the future, so new event types will only be
|
|
added in new versions (note that this is a change over zmq_socket_monitor and the
|
|
unversioned ZMQ_EVENT_ALL).
|
|
|
|
Note that event_version 2 is currently in DRAFT mode. The protocol may be
|
|
changed at any time for event_versions in DRAFT.
|
|
|
|
ZMQ_CURRENT_EVENT_VERSION and ZMQ_CURRENT_EVENT_VERSION_DRAFT are always defined
|
|
to the most recent stable or DRAFT event version, which are currently 1 resp. 2
|
|
|
|
This page describes the protocol for 'event_version' 2 only. For the protocol
|
|
used with 'event_version' 1, please refer to linkzmq:zmq_socket_monitor[3].
|
|
|
|
Each event is sent in multiple frames. The first frame contains an event
|
|
number (64 bits). The number and content of further frames depend on this
|
|
event number.
|
|
|
|
Unless it is specified differently, the second frame contains the number of
|
|
value frames that will follow it as a 64 bits integer. The third frame to N-th
|
|
frames contain an event value (64 bits) that provides additional data according
|
|
to the event number. Each event type might have a different number of values.
|
|
The second-to-last and last frames contain strings that specifies the affected
|
|
connection or endpoint. The former frame contains a string denoting the local
|
|
endpoint, while the latter frame contains a string denoting the remote endpoint.
|
|
Either of these may be empty, depending on the event type and whether the
|
|
connection uses a bound or connected local endpoint.
|
|
|
|
Note that the format of the second and further frames, and also the number of
|
|
frames, may be different for events added in the future.
|
|
|
|
The _zmq_socket_monitor_pipes_stats()_ method triggers an event of type
|
|
ZMQ_EVENT_PIPES_STATS for each connected peer of the monitored socket.
|
|
NOTE: _zmq_socket_monitor_pipes_stats()_ is in DRAFT state.
|
|
|
|
----
|
|
Monitoring events are only generated by some transports: At the moment these
|
|
are SOCKS, TCP, IPC, and TIPC. Note that it is not an error to call
|
|
'zmq_socket_monitor_versioned' on a socket that is connected or bound to some
|
|
other transport, as this may not be known at the time
|
|
'zmq_socket_monitor_versioned' is called. Also, a socket can be connected/bound
|
|
to multiple endpoints using different transports.
|
|
|
|
----
|
|
|
|
Supported events (v1)
|
|
----------------
|
|
|
|
ZMQ_EVENT_CONNECTED
|
|
~~~~~~~~~~~~~~~~~~~
|
|
The socket has successfully connected to a remote peer. The event value
|
|
is the file descriptor (FD) of the underlying network socket. Warning:
|
|
there is no guarantee that the FD is still valid by the time your code
|
|
receives this event.
|
|
|
|
ZMQ_EVENT_CONNECT_DELAYED
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
A connect request on the socket is pending. The event value is unspecified.
|
|
|
|
ZMQ_EVENT_CONNECT_RETRIED
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
A connect request failed, and is now being retried. The event value is the
|
|
reconnect interval in milliseconds. Note that the reconnect interval is
|
|
recalculated for each retry.
|
|
|
|
ZMQ_EVENT_LISTENING
|
|
~~~~~~~~~~~~~~~~~~~
|
|
The socket was successfully bound to a network interface. The event value
|
|
is the FD of the underlying network socket. Warning: there is no guarantee
|
|
that the FD is still valid by the time your code receives this event.
|
|
|
|
ZMQ_EVENT_BIND_FAILED
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
The socket could not bind to a given interface. The event value is the
|
|
errno generated by the system bind call.
|
|
|
|
ZMQ_EVENT_ACCEPTED
|
|
~~~~~~~~~~~~~~~~~~
|
|
The socket has accepted a connection from a remote peer. The event value is
|
|
the FD of the underlying network socket. Warning: there is no guarantee that
|
|
the FD is still valid by the time your code receives this event.
|
|
|
|
ZMQ_EVENT_ACCEPT_FAILED
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
The socket has rejected a connection from a remote peer. The event value is
|
|
the errno generated by the accept call.
|
|
|
|
ZMQ_EVENT_CLOSED
|
|
~~~~~~~~~~~~~~~~
|
|
The socket was closed. The event value is the FD of the (now closed) network
|
|
socket.
|
|
|
|
ZMQ_EVENT_CLOSE_FAILED
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
The socket close failed. The event value is the errno returned by the system
|
|
call. Note that this event occurs only on IPC transports.
|
|
|
|
ZMQ_EVENT_DISCONNECTED
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
The socket was disconnected unexpectedly. The event value is the FD of the
|
|
underlying network socket. Warning: this socket will be closed.
|
|
|
|
ZMQ_EVENT_MONITOR_STOPPED
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Monitoring on this socket ended.
|
|
|
|
ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Unspecified error during handshake.
|
|
The event value is an errno.
|
|
|
|
ZMQ_EVENT_HANDSHAKE_SUCCEEDED
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
The ZMTP security mechanism handshake succeeded.
|
|
The event value is unspecified.
|
|
|
|
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
The ZMTP security mechanism handshake failed due to some mechanism protocol
|
|
error, either between the ZMTP mechanism peers, or between the mechanism
|
|
server and the ZAP handler. This indicates a configuration or implementation
|
|
error in either peer resp. the ZAP handler.
|
|
The event value is one of the ZMQ_PROTOCOL_ERROR_* values:
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
|
|
ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH
|
|
ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED
|
|
ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY
|
|
ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID
|
|
ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION
|
|
ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE
|
|
ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA
|
|
|
|
ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
The ZMTP security mechanism handshake failed due to an authentication failure.
|
|
The event value is the status code returned by the ZAP handler (i.e. 300,
|
|
400 or 500).
|
|
|
|
----
|
|
|
|
Supported events (v2)
|
|
----------------
|
|
|
|
ZMQ_EVENT_PIPE_STATS
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
This event provides two values, the number of messages in each of the two
|
|
queues associated with the returned endpoint (respectively egress and ingress).
|
|
This event only triggers after calling the function
|
|
_zmq_socket_monitor_pipes_stats()_.
|
|
NOTE: this measurement is asynchronous, so by the time the message is received
|
|
the internal state might have already changed.
|
|
NOTE: when the monitored socket and the monitor are not used in a poll, the
|
|
event might not be delivered until an API has been called on the monitored
|
|
socket, like zmq_getsockopt for example (the option is irrelevant).
|
|
NOTE: in DRAFT state, not yet available in stable releases.
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
------------
|
|
The _zmq_socket_monitor()_ and _zmq_socket_monitor_pipes_stats()_ functions
|
|
return a value of 0 or greater if successful. Otherwise they return `-1` and
|
|
set 'errno' to one of the values defined below.
|
|
|
|
|
|
ERRORS - _zmq_socket_monitor()_
|
|
-------------------------------
|
|
*ETERM*::
|
|
The 0MQ 'context' associated with the specified 'socket' was terminated.
|
|
|
|
*EPROTONOSUPPORT*::
|
|
The transport protocol of the monitor 'endpoint' is not supported. Monitor
|
|
sockets are required to use the inproc:// transport.
|
|
|
|
*EINVAL*::
|
|
The monitor 'endpoint' supplied does not exist.
|
|
|
|
|
|
ERRORS - _zmq_socket_monitor_pipes_stats()_
|
|
-------------------------------------------
|
|
*ENOTSOCK*::
|
|
The 'socket' parameter was not a valid 0MQ socket.
|
|
|
|
*EINVAL*::
|
|
The socket did not have monitoring enabled.
|
|
|
|
*EAGAIN*::
|
|
The monitored socket did not have any connections to monitor yet.
|
|
|
|
EXAMPLE
|
|
-------
|
|
.Monitoring client and server sockets
|
|
----
|
|
// Read one event off the monitor socket; return values and addresses
|
|
// by reference, if not null, and event number by value. Returns -1
|
|
// in case of error.
|
|
|
|
static uint64_t
|
|
get_monitor_event (void *monitor, uint64_t *value, char **local_address, char **remote_address)
|
|
{
|
|
// First frame in message contains event number
|
|
zmq_msg_t msg;
|
|
zmq_msg_init (&msg);
|
|
if (zmq_msg_recv (&msg, monitor, 0) == -1)
|
|
return -1; // Interrupted, presumably
|
|
assert (zmq_msg_more (&msg));
|
|
|
|
uint64_t event;
|
|
memcpy (&event, zmq_msg_data (&msg), sizeof (event));
|
|
zmq_msg_close (&msg);
|
|
|
|
// Second frame in message contains the number of values
|
|
zmq_msg_init (&msg);
|
|
if (zmq_msg_recv (&msg, monitor, 0) == -1)
|
|
return -1; // Interrupted, presumably
|
|
assert (zmq_msg_more (&msg));
|
|
|
|
uint64_t value_count;
|
|
memcpy (&value_count, zmq_msg_data (&msg), sizeof (value_count));
|
|
zmq_msg_close (&msg);
|
|
|
|
for (uint64_t i = 0; i < value_count; ++i) {
|
|
// Subsequent frames in message contain event values
|
|
zmq_msg_init (&msg);
|
|
if (zmq_msg_recv (&msg, monitor, 0) == -1)
|
|
return -1; // Interrupted, presumably
|
|
assert (zmq_msg_more (&msg));
|
|
|
|
if (value_ && value_ + i)
|
|
memcpy (value_ + i, zmq_msg_data (&msg), sizeof (*value_));
|
|
zmq_msg_close (&msg);
|
|
}
|
|
|
|
// Second-to-last frame in message contains local address
|
|
zmq_msg_init (&msg);
|
|
if (zmq_msg_recv (&msg, monitor, 0) == -1)
|
|
return -1; // Interrupted, presumably
|
|
assert (zmq_msg_more (&msg));
|
|
|
|
if (local_address_) {
|
|
uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
|
|
size_t size = zmq_msg_size (&msg);
|
|
*local_address_ = (char *) malloc (size + 1);
|
|
memcpy (*local_address_, data, size);
|
|
(*local_address_)[size] = 0;
|
|
}
|
|
zmq_msg_close (&msg);
|
|
|
|
// Last frame in message contains remote address
|
|
zmq_msg_init (&msg);
|
|
if (zmq_msg_recv (&msg, monitor, 0) == -1)
|
|
return -1; // Interrupted, presumably
|
|
assert (!zmq_msg_more (&msg));
|
|
|
|
if (remote_address_) {
|
|
uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
|
|
size_t size = zmq_msg_size (&msg);
|
|
*remote_address_ = (char *) malloc (size + 1);
|
|
memcpy (*remote_address_, data, size);
|
|
(*remote_address_)[size] = 0;
|
|
}
|
|
zmq_msg_close (&msg);
|
|
|
|
return event;
|
|
}
|
|
|
|
int main (void)
|
|
{
|
|
void *ctx = zmq_ctx_new ();
|
|
assert (ctx);
|
|
|
|
// We'll monitor these two sockets
|
|
void *client = zmq_socket (ctx, ZMQ_DEALER);
|
|
assert (client);
|
|
void *server = zmq_socket (ctx, ZMQ_DEALER);
|
|
assert (server);
|
|
|
|
// Socket monitoring only works over inproc://
|
|
int rc = zmq_socket_monitor_versioned (client, "tcp://127.0.0.1:9999", 0, 2);
|
|
assert (rc == -1);
|
|
assert (zmq_errno () == EPROTONOSUPPORT);
|
|
|
|
// Monitor all events on client and server sockets
|
|
rc = zmq_socket_monitor_versioned (client, "inproc://monitor-client", ZMQ_EVENT_ALL, 2);
|
|
assert (rc == 0);
|
|
rc = zmq_socket_monitor_versioned (server, "inproc://monitor-server", ZMQ_EVENT_ALL, 2);
|
|
assert (rc == 0);
|
|
|
|
// Create two sockets for collecting monitor events
|
|
void *client_mon = zmq_socket (ctx, ZMQ_PAIR);
|
|
assert (client_mon);
|
|
void *server_mon = zmq_socket (ctx, ZMQ_PAIR);
|
|
assert (server_mon);
|
|
|
|
// Connect these to the inproc endpoints so they'll get events
|
|
rc = zmq_connect (client_mon, "inproc://monitor-client");
|
|
assert (rc == 0);
|
|
rc = zmq_connect (server_mon, "inproc://monitor-server");
|
|
assert (rc == 0);
|
|
|
|
// Now do a basic ping test
|
|
rc = zmq_bind (server, "tcp://127.0.0.1:9998");
|
|
assert (rc == 0);
|
|
rc = zmq_connect (client, "tcp://127.0.0.1:9998");
|
|
assert (rc == 0);
|
|
bounce (client, server);
|
|
|
|
// Close client and server
|
|
close_zero_linger (client);
|
|
close_zero_linger (server);
|
|
|
|
// Now collect and check events from both sockets
|
|
int event = get_monitor_event (client_mon, NULL, NULL);
|
|
if (event == ZMQ_EVENT_CONNECT_DELAYED)
|
|
event = get_monitor_event (client_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_CONNECTED);
|
|
event = get_monitor_event (client_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_MONITOR_STOPPED);
|
|
|
|
// This is the flow of server events
|
|
event = get_monitor_event (server_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_LISTENING);
|
|
event = get_monitor_event (server_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_ACCEPTED);
|
|
event = get_monitor_event (server_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_CLOSED);
|
|
event = get_monitor_event (server_mon, NULL, NULL);
|
|
assert (event == ZMQ_EVENT_MONITOR_STOPPED);
|
|
|
|
// Close down the sockets
|
|
close_zero_linger (client_mon);
|
|
close_zero_linger (server_mon);
|
|
zmq_ctx_term (ctx);
|
|
|
|
return 0 ;
|
|
}
|
|
----
|
|
|
|
|
|
SEE ALSO
|
|
--------
|
|
linkzmq:zmq[7]
|
|
|
|
|
|
AUTHORS
|
|
-------
|
|
This page was written by the 0MQ community. To make a change please
|
|
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.
|