1ZBEACON(3) CZMQ Manual ZBEACON(3)
2
3
4
6 zbeacon - Class for LAN discovery and presence
7
9 // Create new zbeacon actor instance:
10 //
11 // zactor_t *beacon = zactor_new (zbeacon, NULL);
12 //
13 // Destroy zbeacon instance:
14 //
15 // zactor_destroy (&beacon);
16 //
17 // Enable verbose logging of commands and activity:
18 //
19 // zstr_send (beacon, "VERBOSE");
20 //
21 // Configure beacon to run on specified UDP port, and return the name of
22 // the host, which can be used as endpoint for incoming connections. To
23 // force the beacon to operate on a given interface, set the environment
24 // variable ZSYS_INTERFACE, or call zsys_set_interface() before creating
25 // the beacon. If the system does not support UDP broadcasts (lacking a
26 // workable interface), returns an empty hostname:
27 //
28 // // Pictures: 's' = C string, 'i' = int
29 // zsock_send (beacon, "si", "CONFIGURE", port_number);
30 // char *hostname = zstr_recv (beacon);
31 //
32 // Start broadcasting a beacon at a specified interval in msec. The beacon
33 // data can be at most UDP_FRAME_MAX bytes; this constant is defined in
34 // zsys.h to be 255:
35 //
36 // // Pictures: 'b' = byte * data + size_t size
37 // zsock_send (beacon, "sbi", "PUBLISH", data, size, interval);
38 //
39 // Stop broadcasting the beacon:
40 //
41 // zstr_sendx (beacon, "SILENCE", NULL);
42 //
43 // Start listening to beacons from peers. The filter is used to do a prefix
44 // match on received beacons, to remove junk. Note that any received data
45 // that is identical to our broadcast beacon_data is discarded in any case.
46 // If the filter size is zero, we get all peer beacons:
47 //
48 // zsock_send (beacon, "sb", "SUBSCRIBE", filter_data, filter_size);
49 //
50 // Stop listening to other peers
51 //
52 // zstr_sendx (beacon, "UNSUBSCRIBE", NULL);
53 //
54 // Receive next beacon from a peer. Received beacons are always a 2-frame
55 // message containing the ipaddress of the sender, and then the binary
56 // beacon data as published by the sender:
57 //
58 // zmsg_t *msg = zmsg_recv (beacon);
59 //
60 // This is the zbeacon constructor as a zactor_fn:
61 CZMQ_EXPORT void
62 zbeacon (zsock_t *pipe, void *unused);
63
64 // Self test of this class
65 CZMQ_EXPORT void
66 zbeacon_test (bool verbose);
67 Please add '@interface' section in './../src/zbeacon.c'.
68
70 The zbeacon class implements a peer-to-peer discovery service for local
71 networks. A beacon can broadcast and/or capture service announcements
72 using UDP messages on the local area network. This implementation uses
73 IPv4 UDP broadcasts. You can define the format of your outgoing
74 beacons, and set a filter that validates incoming beacons. Beacons are
75 sent and received asynchronously in the background.
76
77 This class replaces zbeacon_v2, and is meant for applications that use
78 the CZMQ v3 API (meaning, zsock).
79
81 From zbeacon_test method.
82
83 // Test 1 - two beacons, one speaking, one listening
84 // Create speaker beacon to broadcast our service
85 zactor_t *speaker = zactor_new (zbeacon, NULL);
86 assert (speaker);
87 if (verbose)
88 zstr_sendx (speaker, "VERBOSE", NULL);
89
90 zsock_send (speaker, "si", "CONFIGURE", 9999);
91 char *hostname = zstr_recv (speaker);
92 if (!*hostname) {
93 printf ("OK (skipping test, no UDP broadcasting)\n");
94 zactor_destroy (&speaker);
95 freen (hostname);
96 return;
97 }
98 freen (hostname);
99
100 // Create listener beacon on port 9999 to lookup service
101 zactor_t *listener = zactor_new (zbeacon, NULL);
102 assert (listener);
103 if (verbose)
104 zstr_sendx (listener, "VERBOSE", NULL);
105 zsock_send (listener, "si", "CONFIGURE", 9999);
106 hostname = zstr_recv (listener);
107 assert (*hostname);
108 freen (hostname);
109
110 // We will broadcast the magic value 0xCAFE
111 byte announcement [2] = { 0xCA, 0xFE };
112 zsock_send (speaker, "sbi", "PUBLISH", announcement, 2, 100);
113 // We will listen to anything (empty subscription)
114 zsock_send (listener, "sb", "SUBSCRIBE", "", 0);
115
116 // Wait for at most 1/2 second if there's no broadcasting
117 zsock_set_rcvtimeo (listener, 500);
118 char *ipaddress = zstr_recv (listener);
119 if (ipaddress) {
120 zframe_t *content = zframe_recv (listener);
121 assert (zframe_size (content) == 2);
122 assert (zframe_data (content) [0] == 0xCA);
123 assert (zframe_data (content) [1] == 0xFE);
124 zframe_destroy (&content);
125 zstr_free (&ipaddress);
126 zstr_sendx (speaker, "SILENCE", NULL);
127 }
128 zactor_destroy (&listener);
129 zactor_destroy (&speaker);
130
131 // Test subscription filter using a 3-node setup
132 zactor_t *node1 = zactor_new (zbeacon, NULL);
133 assert (node1);
134 zsock_send (node1, "si", "CONFIGURE", 5670);
135 hostname = zstr_recv (node1);
136 assert (*hostname);
137 freen (hostname);
138
139 zactor_t *node2 = zactor_new (zbeacon, NULL);
140 assert (node2);
141 zsock_send (node2, "si", "CONFIGURE", 5670);
142 hostname = zstr_recv (node2);
143 assert (*hostname);
144 freen (hostname);
145
146 zactor_t *node3 = zactor_new (zbeacon, NULL);
147 assert (node3);
148 zsock_send (node3, "si", "CONFIGURE", 5670);
149 hostname = zstr_recv (node3);
150 assert (*hostname);
151 freen (hostname);
152
153 zsock_send (node1, "sbi", "PUBLISH", "NODE/1", 6, 250);
154 zsock_send (node2, "sbi", "PUBLISH", "NODE/2", 6, 250);
155 zsock_send (node3, "sbi", "PUBLISH", "RANDOM", 6, 250);
156 zsock_send (node1, "sb", "SUBSCRIBE", "NODE", 4);
157
158 // Poll on three API sockets at once
159 zpoller_t *poller = zpoller_new (node1, node2, node3, NULL);
160 assert (poller);
161 int64_t stop_at = zclock_mono () + 1000;
162 while (zclock_mono () < stop_at) {
163 long timeout = (long) (stop_at - zclock_mono ());
164 if (timeout < 0)
165 timeout = 0;
166 void *which = zpoller_wait (poller, timeout);
167 if (which) {
168 assert (which == node1);
169 char *ipaddress, *received;
170 zstr_recvx (node1, &ipaddress, &received, NULL);
171 assert (streq (received, "NODE/2"));
172 zstr_free (&ipaddress);
173 zstr_free (&received);
174 }
175 }
176 zpoller_destroy (&poller);
177
178 // Stop listening
179 zstr_sendx (node1, "UNSUBSCRIBE", NULL);
180
181 // Stop all node broadcasts
182 zstr_sendx (node1, "SILENCE", NULL);
183 zstr_sendx (node2, "SILENCE", NULL);
184 zstr_sendx (node3, "SILENCE", NULL);
185
186 // Destroy the test nodes
187 zactor_destroy (&node1);
188 zactor_destroy (&node2);
189 zactor_destroy (&node3);
190
191 // Unset multicast
192 zsys_set_ipv4_mcast_address (NULL);
193
194 // Test 1 - two beacons, one speaking, one listening
195 // Create speaker beacon to broadcast our service
196 zactor_t *speaker = zactor_new (zbeacon, NULL);
197 assert (speaker);
198 if (verbose)
199 zstr_sendx (speaker, "VERBOSE", NULL);
200
201 zsock_send (speaker, "si", "CONFIGURE", 9999);
202 char *hostname = zstr_recv (speaker);
203 if (!*hostname) {
204 printf ("OK (skipping test, no UDP broadcasting)\n");
205 zactor_destroy (&speaker);
206 freen (hostname);
207 return;
208 }
209 freen (hostname);
210
211 // Create listener beacon on port 9999 to lookup service
212 zactor_t *listener = zactor_new (zbeacon, NULL);
213 assert (listener);
214 if (verbose)
215 zstr_sendx (listener, "VERBOSE", NULL);
216 zsock_send (listener, "si", "CONFIGURE", 9999);
217 hostname = zstr_recv (listener);
218 assert (*hostname);
219 freen (hostname);
220
221 // We will broadcast the magic value 0xCAFE
222 byte announcement [2] = { 0xCA, 0xFE };
223 zsock_send (speaker, "sbi", "PUBLISH", announcement, 2, 100);
224 // We will listen to anything (empty subscription)
225 zsock_send (listener, "sb", "SUBSCRIBE", "", 0);
226
227 // Wait for at most 1/2 second if there's no broadcasting
228 zsock_set_rcvtimeo (listener, 500);
229 char *ipaddress = zstr_recv (listener);
230 if (ipaddress) {
231 zframe_t *content = zframe_recv (listener);
232 assert (zframe_size (content) == 2);
233 assert (zframe_data (content) [0] == 0xCA);
234 assert (zframe_data (content) [1] == 0xFE);
235 zframe_destroy (&content);
236 zstr_free (&ipaddress);
237 zstr_sendx (speaker, "SILENCE", NULL);
238 }
239 zactor_destroy (&listener);
240 zactor_destroy (&speaker);
241
242 // Test subscription filter using a 3-node setup
243 zactor_t *node1 = zactor_new (zbeacon, NULL);
244 assert (node1);
245 zsock_send (node1, "si", "CONFIGURE", 5670);
246 hostname = zstr_recv (node1);
247 assert (*hostname);
248 freen (hostname);
249
250 zactor_t *node2 = zactor_new (zbeacon, NULL);
251 assert (node2);
252 zsock_send (node2, "si", "CONFIGURE", 5670);
253 hostname = zstr_recv (node2);
254 assert (*hostname);
255 freen (hostname);
256
257 zactor_t *node3 = zactor_new (zbeacon, NULL);
258 assert (node3);
259 zsock_send (node3, "si", "CONFIGURE", 5670);
260 hostname = zstr_recv (node3);
261 assert (*hostname);
262 freen (hostname);
263
264 zsock_send (node1, "sbi", "PUBLISH", "NODE/1", 6, 250);
265 zsock_send (node2, "sbi", "PUBLISH", "NODE/2", 6, 250);
266 zsock_send (node3, "sbi", "PUBLISH", "RANDOM", 6, 250);
267 zsock_send (node1, "sb", "SUBSCRIBE", "NODE", 4);
268
269 // Poll on three API sockets at once
270 zpoller_t *poller = zpoller_new (node1, node2, node3, NULL);
271 assert (poller);
272 int64_t stop_at = zclock_mono () + 1000;
273 while (zclock_mono () < stop_at) {
274 long timeout = (long) (stop_at - zclock_mono ());
275 if (timeout < 0)
276 timeout = 0;
277 void *which = zpoller_wait (poller, timeout);
278 if (which) {
279 assert (which == node1);
280 char *ipaddress, *received;
281 zstr_recvx (node1, &ipaddress, &received, NULL);
282 assert (streq (received, "NODE/2"));
283 zstr_free (&ipaddress);
284 zstr_free (&received);
285 }
286 }
287 zpoller_destroy (&poller);
288
289 // Stop listening
290 zstr_sendx (node1, "UNSUBSCRIBE", NULL);
291
292 // Stop all node broadcasts
293 zstr_sendx (node1, "SILENCE", NULL);
294 zstr_sendx (node2, "SILENCE", NULL);
295 zstr_sendx (node3, "SILENCE", NULL);
296
297 // Destroy the test nodes
298 zactor_destroy (&node1);
299 zactor_destroy (&node2);
300 zactor_destroy (&node3);
301
302 #if defined (__WINDOWS__)
303 zsys_shutdown();
304 #endif
305
306
308 The czmq manual was written by the authors in the AUTHORS file.
309
311 Main web site:
312
313 Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
314
316 Copyright (c) the Contributors as noted in the AUTHORS file. This file
317 is part of CZMQ, the high-level C binding for 0MQ:
318 http://czmq.zeromq.org. This Source Code Form is subject to the terms
319 of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
320 distributed with this file, You can obtain one at
321 http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
322 distribution.
323
325 1. zeromq-dev@lists.zeromq.org
326 mailto:zeromq-dev@lists.zeromq.org
327
328
329
330CZMQ 4.2.1 07/20/2022 ZBEACON(3)