multicast
stableSend and receive UDP multicast datagrams over IPv4 using a real OS socket, with support for TTL, loopback control, and binary payloads.
use plugin multicast::{is_multicast, multicast_range, MulticastSocket.new, …} Functions (14)
- is_multicast Check if an IPv4 address is in the multicast range
- multicast_range Return the IPv4 multicast address range
- MulticastSocket.new Open a socket and join an IPv4 multicast group
- send Send a string datagram to the group
- recv Receive a string datagram (blocking)
- send_bytes Send a raw binary datagram to the group
- recv_bytes Receive a raw binary datagram (blocking)
- leave Leave the multicast group
- local_addr Return the bound local address string
- set_ttl Set the multicast TTL (hop limit)
- set_loopback Enable or disable multicast loopback
- set_timeout Set read/write timeout in milliseconds
- group_addr Return the multicast group address
- port Return the bound port number
Overview
multicast lets Zolo programs join an IPv4 multicast group and exchange UDP
datagrams with every other member of that group over a real operating-system
socket. The core type is the MulticastSocket handle: calling
MulticastSocket.new(group_addr, port) validates the group address, binds to
0.0.0.0:<port>, and joins the group on all interfaces with loopback enabled.
You then call instance methods on that handle to send and receive data, tune the
hop limit and loopback behaviour, and finally leave the group.
Use it for local-network service discovery (mDNS-style announcements), one-to-many
event fan-out, or any scenario where you want to broadcast to many listeners
without tracking each peer individually. The plugin works with both text payloads
(send / recv) and raw binary payloads (send_bytes / recv_bytes), and the
two free functions is_multicast and multicast_range help you validate and
reason about multicast address ranges before opening a socket.
Common patterns
Open a socket, announce a message, then read replies with a timeout so the receive call does not block forever:
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
print("joined {sock.group_addr()} on port {sock.port()}")
let sent = sock.send("hello group")
print("sent {sent} bytes from {sock.local_addr()}")
sock.set_timeout(1000)
let msg = sock.recv(1024)
print("from {msg["addr"]}: {msg["data"]}")
sock.leave()
Validate an address before binding so you never hand a unicast address to the constructor:
use plugin multicast::{MulticastSocket, is_multicast, multicast_range}
let group = "224.0.0.251"
let range = multicast_range()
if is_multicast(group) {
print("{group} is valid (range {range["start"]} - {range["end"]})")
let sock = MulticastSocket.new(group, 5353)
sock.set_ttl(1)
sock.leave()
}
Send and receive a raw binary payload, keeping the datagram off the host loop:
use plugin multicast::{MulticastSocket}
let sender = MulticastSocket.new("224.0.0.251", 5353)
sender.set_loopback(false)
let payload = [0x00, 0x01, 0x02, 0x03]
let n = sender.send_bytes(payload)
print("sent {n} raw bytes")
let receiver = MulticastSocket.new("224.0.0.251", 5353)
receiver.set_timeout(500)
let result = receiver.recv_bytes(512)
print("received from {result["addr"]}")
Check if an IPv4 address is in the multicast range
Returns true if the given IPv4 address string falls within the multicast range
224.0.0.0 to 239.255.255.255. Any address that fails to parse, or that lies
outside the range, returns false rather than erroring.
use plugin multicast::{is_multicast}
print(is_multicast("224.0.0.1"))
print(is_multicast("192.168.1.1"))
Use it as a guard before constructing a socket so an invalid group address never reaches the OS:
use plugin multicast::{MulticastSocket, is_multicast}
let group = "239.255.0.10"
if is_multicast(group) {
let sock = MulticastSocket.new(group, 6000)
sock.leave()
}
Return the IPv4 multicast address range
Returns a table with start and end fields describing the full IPv4 multicast
address range (224.0.0.0 through 239.255.255.255).
use plugin multicast::{multicast_range}
let range = multicast_range()
print("{range["start"]} - {range["end"]}")
Open a socket and join an IPv4 multicast group
Opens a real OS UDP socket, binds it to 0.0.0.0:<port>, and joins the given
IPv4 multicast group on all interfaces. The constructor validates that
group_addr is a multicast address (224.x.x.x–239.x.x.x) and enables
multicast loopback by default, so the local host also receives its own
datagrams. It returns a MulticastSocket handle used by every instance method.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
print("joined {sock.group_addr()} on {sock.port()}")
sock.leave()
Send a string datagram to the group
Sends a string datagram to the joined multicast group and returns the number of bytes written. The destination is always the socket's own group and port.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
let n = sock.send("status: ok")
print("sent {n} bytes")
sock.leave()
Pair it with a timeout-bounded recv to implement a simple request/response:
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
sock.send("ping")
sock.set_timeout(1000)
let reply = sock.recv(256)
print("got: {reply["data"]}")
sock.leave()
Receive a string datagram (blocking)
Blocks until a datagram arrives, reading at most max_bytes bytes, and returns a
table with a data field (the message as a string) and an addr field (the
sender's ip:port). If a timeout was set with set_timeout, the call errors
when the deadline passes instead of blocking indefinitely.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
let msg = sock.recv(1024)
print("from {msg["addr"]}: {msg["data"]}")
sock.leave()
Send a raw binary datagram to the group
Sends a raw binary datagram (an array of byte values) to the group and returns
the number of bytes written. Use this instead of send when the payload is not
valid UTF-8 text.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("224.0.0.251", 5353)
let n = sock.send_bytes([0xDE, 0xAD, 0xBE, 0xEF])
print("sent {n} raw bytes")
sock.leave()
Receive a raw binary datagram (blocking)
Blocks until a datagram arrives, reading at most max_bytes bytes, and returns a
table with a data field holding the raw bytes and an addr field with the
sender's address. This is the binary counterpart to recv.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("224.0.0.251", 5353)
sock.set_timeout(500)
let result = sock.recv_bytes(512)
print("received from {result["addr"]}")
sock.leave()
Leave the multicast group
Leaves the multicast group on all interfaces. Call this when you are done so the host stops receiving group traffic.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
sock.send("goodbye")
sock.leave()
Return the bound local address string
Returns the socket's bound local address as an ip:port string (for example
"0.0.0.0:5007").
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
print("bound to {sock.local_addr()}")
sock.leave()
Set the multicast TTL (hop limit)
Sets the multicast TTL (time-to-live / hop limit) for outgoing datagrams. A TTL
of 1 keeps traffic on the local subnet; larger values allow it to cross that
many routers.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("224.0.0.251", 5353)
sock.set_ttl(1)
sock.send("local only")
sock.leave()
Enable or disable multicast loopback
Enables or disables multicast loopback. When enabled (the default), the sending host also receives its own datagrams; disable it to suppress that echo.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("224.0.0.251", 5353)
sock.set_loopback(false)
sock.send("not echoed locally")
sock.leave()
Set read/write timeout in milliseconds
Sets both the read and write timeout in milliseconds. A positive value makes
recv / recv_bytes error out after that many milliseconds with no data;
passing 0 (or a non-positive value) restores fully blocking behaviour.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
sock.set_timeout(2000)
let msg = sock.recv(1024)
print(msg["data"])
sock.leave()
Return the multicast group address
Returns the multicast group address the socket joined, as a string.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
print("group: {sock.group_addr()}")
sock.leave()
Return the bound port number
Returns the port number the socket is bound to.
use plugin multicast::{MulticastSocket}
let sock = MulticastSocket.new("239.0.0.1", 5007)
print("port: {sock.port()}")
sock.leave()