Skip to content

multicast

stable

Send 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, …}
14 functions Networking
/ filter jk navigate Esc clear
Functions (14)
  1. is_multicast Check if an IPv4 address is in the multicast range
  2. multicast_range Return the IPv4 multicast address range
  3. MulticastSocket.new Open a socket and join an IPv4 multicast group
  4. send Send a string datagram to the group
  5. recv Receive a string datagram (blocking)
  6. send_bytes Send a raw binary datagram to the group
  7. recv_bytes Receive a raw binary datagram (blocking)
  8. leave Leave the multicast group
  9. local_addr Return the bound local address string
  10. set_ttl Set the multicast TTL (hop limit)
  11. set_loopback Enable or disable multicast loopback
  12. set_timeout Set read/write timeout in milliseconds
  13. group_addr Return the multicast group address
  14. 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.x239.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()
enespt-br