'\" t .\" Title: zmsg .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 03/02/2024 .\" Manual: CZMQ Manual .\" Source: CZMQ 4.2.1 .\" Language: English .\" .TH "ZMSG" "3" "03/02/2024" "CZMQ 4\&.2\&.1" "CZMQ Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" zmsg \- Class for working with multipart messages .SH "SYNOPSIS" .sp .nf // This is a stable class, and may not change except for emergencies\&. It // is provided in stable builds\&. // This class has draft methods, which may change over time\&. They are not // in stable releases, by default\&. Use \-\-enable\-drafts to enable\&. // Create a new empty message object CZMQ_EXPORT zmsg_t * zmsg_new (void); // Receive message from socket, returns zmsg_t object or NULL if the recv // was interrupted\&. Does a blocking recv\&. If you want to not block then use // the zloop class or zmsg_recv_nowait or zmq_poll to check for socket input // before receiving\&. CZMQ_EXPORT zmsg_t * zmsg_recv (void *source); // Load/append an open file into new message, return the message\&. // Returns NULL if the message could not be loaded\&. CZMQ_EXPORT zmsg_t * zmsg_load (FILE *file); // Decodes a serialized message frame created by zmsg_encode () and returns // a new zmsg_t object\&. Returns NULL if the frame was badly formatted or // there was insufficient memory to work\&. CZMQ_EXPORT zmsg_t * zmsg_decode (zframe_t *frame); // Generate a signal message encoding the given status\&. A signal is a short // message carrying a 1\-byte success/failure code (by convention, 0 means // OK)\&. Signals are encoded to be distinguishable from "normal" messages\&. CZMQ_EXPORT zmsg_t * zmsg_new_signal (byte status); // Destroy a message object and all frames it contains CZMQ_EXPORT void zmsg_destroy (zmsg_t **self_p); // Send message to destination socket, and destroy the message after sending // it successfully\&. If the message has no frames, sends nothing but destroys // the message anyhow\&. Nullifies the caller\*(Aqs reference to the message (as // it is a destructor)\&. CZMQ_EXPORT int zmsg_send (zmsg_t **self_p, void *dest); // Send message to destination socket as part of a multipart sequence, and // destroy the message after sending it successfully\&. Note that after a // zmsg_sendm, you must call zmsg_send or another method that sends a final // message part\&. If the message has no frames, sends nothing but destroys // the message anyhow\&. Nullifies the caller\*(Aqs reference to the message (as // it is a destructor)\&. CZMQ_EXPORT int zmsg_sendm (zmsg_t **self_p, void *dest); // Return size of message, i\&.e\&. number of frames (0 or more)\&. CZMQ_EXPORT size_t zmsg_size (zmsg_t *self); // Return total size of all frames in message\&. CZMQ_EXPORT size_t zmsg_content_size (zmsg_t *self); // Push frame to the front of the message, i\&.e\&. before all other frames\&. // Message takes ownership of frame, will destroy it when message is sent\&. // Returns 0 on success, \-1 on error\&. Deprecates zmsg_push, which did not // nullify the caller\*(Aqs frame reference\&. CZMQ_EXPORT int zmsg_prepend (zmsg_t *self, zframe_t **frame_p); // Add frame to the end of the message, i\&.e\&. after all other frames\&. // Message takes ownership of frame, will destroy it when message is sent\&. // Returns 0 on success\&. Deprecates zmsg_add, which did not nullify the // caller\*(Aqs frame reference\&. CZMQ_EXPORT int zmsg_append (zmsg_t *self, zframe_t **frame_p); // Remove first frame from message, if any\&. Returns frame, or NULL\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zframe_t * zmsg_pop (zmsg_t *self); // Push block of memory to front of message, as a new frame\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_pushmem (zmsg_t *self, const void *data, size_t size); // Add block of memory to the end of the message, as a new frame\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_addmem (zmsg_t *self, const void *data, size_t size); // Push string as new frame to front of message\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_pushstr (zmsg_t *self, const char *string); // Push string as new frame to end of message\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_addstr (zmsg_t *self, const char *string); // Push formatted string as new frame to front of message\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_pushstrf (zmsg_t *self, const char *format, \&.\&.\&.) CHECK_PRINTF (2); // Push formatted string as new frame to end of message\&. // Returns 0 on success, \-1 on error\&. CZMQ_EXPORT int zmsg_addstrf (zmsg_t *self, const char *format, \&.\&.\&.) CHECK_PRINTF (2); // Pop frame off front of message, return as fresh string\&. If there were // no more frames in the message, returns NULL\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT char * zmsg_popstr (zmsg_t *self); // Push encoded message as a new frame\&. Message takes ownership of // submessage, so the original is destroyed in this call\&. Returns 0 on // success, \-1 on error\&. CZMQ_EXPORT int zmsg_addmsg (zmsg_t *self, zmsg_t **msg_p); // Remove first submessage from message, if any\&. Returns zmsg_t, or NULL if // decoding was not successful\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zmsg_t * zmsg_popmsg (zmsg_t *self); // Remove specified frame from list, if present\&. Does not destroy frame\&. CZMQ_EXPORT void zmsg_remove (zmsg_t *self, zframe_t *frame); // Set cursor to first frame in message\&. Returns frame, or NULL, if the // message is empty\&. Use this to navigate the frames as a list\&. CZMQ_EXPORT zframe_t * zmsg_first (zmsg_t *self); // Return the next frame\&. If there are no more frames, returns NULL\&. To move // to the first frame call zmsg_first()\&. Advances the cursor\&. CZMQ_EXPORT zframe_t * zmsg_next (zmsg_t *self); // Return the last frame\&. If there are no frames, returns NULL\&. CZMQ_EXPORT zframe_t * zmsg_last (zmsg_t *self); // Save message to an open file, return 0 if OK, else \-1\&. The message is // saved as a series of frames, each with length and data\&. Note that the // file is NOT guaranteed to be portable between operating systems, not // versions of CZMQ\&. The file format is at present undocumented and liable // to arbitrary change\&. CZMQ_EXPORT int zmsg_save (zmsg_t *self, FILE *file); // Serialize multipart message to a single message frame\&. Use this method // to send structured messages across transports that do not support // multipart data\&. Allocates and returns a new frame containing the // serialized message\&. To decode a serialized message frame, use // zmsg_decode ()\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zframe_t * zmsg_encode (zmsg_t *self); // Create copy of message, as new message object\&. Returns a fresh zmsg_t // object\&. If message is null, or memory was exhausted, returns null\&. // Caller owns return value and must destroy it when done\&. CZMQ_EXPORT zmsg_t * zmsg_dup (zmsg_t *self); // Send message to zsys log sink (may be stdout, or system facility as // configured by zsys_set_logstream)\&. // Long messages are truncated\&. CZMQ_EXPORT void zmsg_print (zmsg_t *self); // Return true if the two messages have the same number of frames and each // frame in the first message is identical to the corresponding frame in the // other message\&. As with zframe_eq, return false if either message is NULL\&. CZMQ_EXPORT bool zmsg_eq (zmsg_t *self, zmsg_t *other); // Return signal value, 0 or greater, if message is a signal, \-1 if not\&. CZMQ_EXPORT int zmsg_signal (zmsg_t *self); // Probe the supplied object, and report if it looks like a zmsg_t\&. CZMQ_EXPORT bool zmsg_is (void *self); // Self test of this class\&. CZMQ_EXPORT void zmsg_test (bool verbose); #ifdef CZMQ_BUILD_DRAFT_API // *** Draft method, for development use, may change without warning *** // Return message routing ID, if the message came from a ZMQ_SERVER socket\&. // Else returns zero\&. CZMQ_EXPORT uint32_t zmsg_routing_id (zmsg_t *self); // *** Draft method, for development use, may change without warning *** // Set routing ID on message\&. This is used if/when the message is sent to a // ZMQ_SERVER socket\&. CZMQ_EXPORT void zmsg_set_routing_id (zmsg_t *self, uint32_t routing_id); // *** Draft method, for development use, may change without warning *** // Send message to zsys log sink (may be stdout, or system facility as // configured by zsys_set_logstream)\&. // Message length is specified; no truncation unless length is zero\&. // Backwards compatible with zframe_print when length is zero\&. CZMQ_EXPORT void zmsg_print_n (zmsg_t *self, size_t size); #endif // CZMQ_BUILD_DRAFT_API Please add \*(Aq@interface\*(Aq section in \*(Aq\&./\&.\&./src/zmsg\&.c\*(Aq\&. .fi .SH "DESCRIPTION" .sp The zmsg class provides methods to send and receive multipart messages across 0MQ sockets\&. This class provides a list\-like container interface, with methods to work with the overall container\&. zmsg_t messages are composed of zero or more zframe_t frames\&. .sp Please add \fI@discuss\fR section in \fI\&./\&.\&./src/zmsg\&.c\fR\&. .SH "EXAMPLE" .PP \fBFrom zmsg_test method\fR. .sp .if n \{\ .RS 4 .\} .nf // Create two PAIR sockets and connect over inproc zsock_t *output = zsock_new_pair ("@inproc://zmsg\&.test"); assert (output); zsock_t *input = zsock_new_pair (">inproc://zmsg\&.test"); assert (input); // Test send and receive of single\-frame message zmsg_t *msg = zmsg_new (); assert (msg); zframe_t *frame = zframe_new ("Hello", 5); assert (frame); zmsg_prepend (msg, &frame); assert (zmsg_size (msg) == 1); assert (zmsg_content_size (msg) == 5); rc = zmsg_send (&msg, output); assert (msg == NULL); assert (rc == 0); msg = zmsg_recv (input); assert (msg); assert (zmsg_size (msg) == 1); assert (zmsg_content_size (msg) == 5); zmsg_destroy (&msg); // Test send and receive of multi\-frame message msg = zmsg_new (); assert (msg); rc = zmsg_addmem (msg, "Frame0", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame1", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame2", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame3", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame4", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame5", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame6", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame7", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame8", 6); assert (rc == 0); rc = zmsg_addmem (msg, "Frame9", 6); assert (rc == 0); zmsg_t *copy = zmsg_dup (msg); assert (copy); rc = zmsg_send (©, output); assert (rc == 0); rc = zmsg_send (&msg, output); assert (rc == 0); copy = zmsg_recv (input); assert (copy); assert (zmsg_size (copy) == 10); assert (zmsg_content_size (copy) == 60); zmsg_destroy (©); msg = zmsg_recv (input); assert (msg); assert (zmsg_size (msg) == 10); assert (zmsg_content_size (msg) == 60); // Save to a file, read back FILE *file = fopen ("zmsg\&.test", "w"); assert (file); rc = zmsg_save (msg, file); assert (rc == 0); fclose (file); file = fopen ("zmsg\&.test", "r"); rc = zmsg_save (msg, file); assert (rc == \-1); fclose (file); zmsg_destroy (&msg); file = fopen ("zmsg\&.test", "r"); msg = zmsg_load (file); assert (msg); fclose (file); remove ("zmsg\&.test"); assert (zmsg_size (msg) == 10); assert (zmsg_content_size (msg) == 60); // Remove all frames except first and last int frame_nbr; for (frame_nbr = 0; frame_nbr < 8; frame_nbr++) { zmsg_first (msg); frame = zmsg_next (msg); zmsg_remove (msg, frame); zframe_destroy (&frame); } // Test message frame manipulation assert (zmsg_size (msg) == 2); frame = zmsg_last (msg); assert (zframe_streq (frame, "Frame9")); assert (zmsg_content_size (msg) == 12); frame = zframe_new ("Address", 7); assert (frame); zmsg_prepend (msg, &frame); assert (zmsg_size (msg) == 3); rc = zmsg_addstr (msg, "Body"); assert (rc == 0); assert (zmsg_size (msg) == 4); frame = zmsg_pop (msg); zframe_destroy (&frame); assert (zmsg_size (msg) == 3); char *body = zmsg_popstr (msg); assert (streq (body, "Frame0")); freen (body); zmsg_destroy (&msg); // Test encoding/decoding msg = zmsg_new (); assert (msg); byte *blank = (byte *) zmalloc (100000); assert (blank); rc = zmsg_addmem (msg, blank, 0); assert (rc == 0); rc = zmsg_addmem (msg, blank, 1); assert (rc == 0); rc = zmsg_addmem (msg, blank, 253); assert (rc == 0); rc = zmsg_addmem (msg, blank, 254); assert (rc == 0); rc = zmsg_addmem (msg, blank, 255); assert (rc == 0); rc = zmsg_addmem (msg, blank, 256); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65535); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65536); assert (rc == 0); rc = zmsg_addmem (msg, blank, 65537); assert (rc == 0); freen (blank); assert (zmsg_size (msg) == 9); frame = zmsg_encode (msg); zmsg_destroy (&msg); msg = zmsg_decode (frame); assert (msg); zmsg_destroy (&msg); zframe_destroy (&frame); // Test submessages msg = zmsg_new (); assert (msg); zmsg_t *submsg = zmsg_new (); zmsg_pushstr (msg, "matr"); zmsg_pushstr (submsg, "joska"); rc = zmsg_addmsg (msg, &submsg); assert (rc == 0); assert (submsg == NULL); submsg = zmsg_popmsg (msg); assert (submsg == NULL); // string "matr" is not encoded zmsg_t, so was discarded submsg = zmsg_popmsg (msg); assert (submsg); body = zmsg_popstr (submsg); assert (streq (body, "joska")); freen (body); zmsg_destroy (&submsg); frame = zmsg_pop (msg); assert (frame == NULL); zmsg_destroy (&msg); // Test comparison of two messages msg = zmsg_new (); zmsg_addstr (msg, "One"); zmsg_addstr (msg, "Two"); zmsg_addstr (msg, "Three"); zmsg_t *msg_other = zmsg_new (); zmsg_addstr (msg_other, "One"); zmsg_addstr (msg_other, "Two"); zmsg_addstr (msg_other, "One\-Hundred"); zmsg_t *msg_dup = zmsg_dup (msg); zmsg_t *empty_msg = zmsg_new (); zmsg_t *empty_msg_2 = zmsg_new (); assert (zmsg_eq (msg, msg_dup)); assert (!zmsg_eq (msg, msg_other)); assert (zmsg_eq (empty_msg, empty_msg_2)); assert (!zmsg_eq (msg, NULL)); assert (!zmsg_eq (NULL, empty_msg)); assert (!zmsg_eq (NULL, NULL)); zmsg_destroy (&msg); zmsg_destroy (&msg_other); zmsg_destroy (&msg_dup); zmsg_destroy (&empty_msg); zmsg_destroy (&empty_msg_2); // Test signal messages msg = zmsg_new_signal (0); assert (zmsg_signal (msg) == 0); zmsg_destroy (&msg); msg = zmsg_new_signal (\-1); assert (zmsg_signal (msg) == 255); zmsg_destroy (&msg); // Now try methods on an empty message msg = zmsg_new (); assert (msg); assert (zmsg_size (msg) == 0); assert (zmsg_unwrap (msg) == NULL); assert (zmsg_first (msg) == NULL); assert (zmsg_last (msg) == NULL); assert (zmsg_next (msg) == NULL); assert (zmsg_pop (msg) == NULL); // Sending an empty message is valid and destroys the message assert (zmsg_send (&msg, output) == 0); assert (!msg); zsock_destroy (&input); zsock_destroy (&output); #if defined (ZMQ_SERVER) // Create server and client sockets and connect over inproc zsock_t *server = zsock_new_server ("inproc://zmsg\-test\-routing"); assert (server); zsock_t *client = zsock_new_client ("inproc://zmsg\-test\-routing"); assert (client); // Send request from client to server zmsg_t *request = zmsg_new (); assert (request); zmsg_addstr (request, "Hello"); rc = zmsg_send (&request, client); assert (rc == 0); assert (!request); // Read request and send reply request = zmsg_recv (server); assert (request); char *string = zmsg_popstr (request); assert (streq (string, "Hello")); assert (zmsg_routing_id (request)); zstr_free (&string); zmsg_t *reply = zmsg_new (); assert (reply); zmsg_addstr (reply, "World"); zmsg_set_routing_id (reply, zmsg_routing_id (request)); rc = zmsg_send (&reply, server); assert (rc == 0); zmsg_destroy (&request); // Read reply reply = zmsg_recv (client); string = zmsg_popstr (reply); assert (streq (string, "World")); assert (zmsg_routing_id (reply) == 0); zmsg_destroy (&reply); zstr_free (&string); // Client and server disallow multipart msg = zmsg_new (); zmsg_addstr (msg, "One"); zmsg_addstr (msg, "Two"); rc = zmsg_send (&msg, client); assert (rc == \-1); assert (zmsg_size (msg) == 2); rc = zmsg_send (&msg, server); assert (rc == \-1); assert (zmsg_size (msg) == 2); zmsg_destroy (&msg); zsock_destroy (&client); zsock_destroy (&server); #endif // Test message length calculation after removal msg = zmsg_new (); zmsg_addstr (msg, "One"); zmsg_addstr (msg, "Two"); size_t size_before = zmsg_content_size (msg); frame = zframe_new ("Three", strlen ("Three")); assert (frame); zmsg_remove (msg, frame); size_t size_after = zmsg_content_size (msg); assert (size_before == size_after); zframe_destroy (&frame); zmsg_destroy (&msg); #if defined (__WINDOWS__) zsys_shutdown(); #endif .fi .if n \{\ .RE .\} .sp .SH "AUTHORS" .sp The czmq manual was written by the authors in the AUTHORS file\&. .SH "RESOURCES" .sp Main web site: \m[blue]\fB\%\fR\m[] .sp Report bugs to the email <\m[blue]\fBzeromq\-dev@lists\&.zeromq\&.org\fR\m[]\&\s-2\u[1]\d\s+2> .SH "COPYRIGHT" .sp Copyright (c) the Contributors as noted in the AUTHORS file\&. This file is part of CZMQ, the high\-level C binding for 0MQ: http://czmq\&.zeromq\&.org\&. This Source Code Form is subject to the terms of the Mozilla Public License, v\&. 2\&.0\&. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla\&.org/MPL/2\&.0/\&. LICENSE included with the czmq distribution\&. .SH "NOTES" .IP " 1." 4 zeromq-dev@lists.zeromq.org .RS 4 \%mailto:zeromq-dev@lists.zeromq.org .RE