Skip to content
This repository was archived by the owner on Oct 30, 2019. It is now read-only.
This repository was archived by the owner on Oct 30, 2019. It is now read-only.

How do we multicast using Rust's net? #81

@nbro

Description

@nbro

I'm using rustc 1.30.1. I am doing everything on the same machine.

Rust's net provides a way to a join a multicast group, using join_multicast_v4. But I am unable to create an example, using just net, where I am able to multicast, that is, send a message to a multicast group B, and all sockets associated with B receive the message.

Here's the code I am using to try to implement multicasting in Rust using just net.

use std::net::Ipv4Addr;
use std::net::UdpSocket;
use std::str::FromStr;
use std::thread;
use std::time::Duration;

fn main() {
    // Host of group A.
    let proposers_host = "239.0.0.1";

    // Host of group B.
    let acceptors_host = "239.0.0.1";

    let acceptors_address = "239.0.0.1:7000";

    let join_handle1: thread::JoinHandle<_> = thread::spawn(move || {
        println!("{}", "Spawning 1st thread");

        let socket = UdpSocket::bind("0.0.0.0:0").expect("Couldn't bind proposer UDP socket");

        // Does NOT work even if I uncomment the following.
        // socket
        //     .set_multicast_loop_v4(true)
        //     .expect("Could not enable multicast loop, to send packets back to the local socket");

        // This socket joined this group. Let's call this group A.
        socket
            .join_multicast_v4(
                &Ipv4Addr::from_str(proposers_host).unwrap(),
                &Ipv4Addr::UNSPECIFIED,
            ).expect("Could not join multicast group A");

        for i in 1..10 {
            // Send message to the acceptors that joined the multicast group B.
            socket
                .send_to(&[i], acceptors_address)
                .expect("couldn't send data");
            println!("Sent message: {:?}\n---\n", i);

            thread::sleep(Duration::from_millis(1));
        }
    });

    let join_handle2: thread::JoinHandle<_> = thread::spawn(move || {
        println!("{}", "Spawning 2nd thread");

        let socket = UdpSocket::bind("0.0.0.0:0").expect("Could not bind acceptor 1 UDP socket");

        // Joining group B.
        socket
            .join_multicast_v4(
                &Ipv4Addr::from_str(acceptors_host).unwrap(),
                &Ipv4Addr::UNSPECIFIED,
            ).expect("Could not join multicast group B");

        let mut buf = [0; 10];
        let mut c = 0;
        loop {
            let (number_of_bytes, src_addr) =
                socket.recv_from(&mut buf).expect("Didn't receive data");

            let filled_buf = &mut buf[..number_of_bytes];

            println!("I am the 2nd socket");
            println!("Message received from address = {:?}", src_addr);
            println!("Contents of the message = {:?}\n---\n", filled_buf);

            thread::sleep(Duration::from_millis(1));

            c += 1;
            if c == 5 {
                break;
            }
        }
    });

    let join_handle3: thread::JoinHandle<_> = thread::spawn(move || {
        println!("{}", "Spawning 3rd thread");

        let socket = UdpSocket::bind("0.0.0.0:0").expect("Could not bind acceptor 2 UDP socket");

        socket
            .join_multicast_v4(
                &Ipv4Addr::from_str(acceptors_host).unwrap(),
                &Ipv4Addr::UNSPECIFIED,
            ).expect("Could not join multicast group B");

        let mut buf = [0; 10];
        loop {
            let (number_of_bytes, src_addr) =
                socket.recv_from(&mut buf).expect("Didn't receive data");

            let filled_buf = &mut buf[..number_of_bytes];

            println!("I am the 3rd socket");
            println!("Message received from address = {:?}", src_addr);
            println!("Contents of the message = {:?}\n---\n", filled_buf);

            thread::sleep(Duration::from_millis(1));
        }
    });

    println!("{}", "At the end");

    join_handle1.join().unwrap();
    join_handle2.join().unwrap();
    join_handle3.join().unwrap();
}

It's not clear to me why Rust's net provides a method join_multicast_v4, but the example above does not work as expected, i.e. the "acceptors" do not receive anything!

I can't bind two sockets to the same port (at least, locally, and I am doing this locally, but eventually acceptors could be in different machines). If I bind socket 2 and 3 to the same port 7000, one of the acceptors (either 2 or 3) receives the messages, but the other panics because I can't bind two sockets to the same port. You can test this behaviour by changing the lines above (in the 2nd and 3rd socket)

let socket = UdpSocket::bind("0.0.0.0:0").expect("...");

to, e.g.,

let socket = UdpSocket::bind("0.0.0.0:7000").expect("...");

And you will get a panic, as I just explained.

So, how do I multicast using Rust's net? Can you please provide a simple example where there are multiple receivers (or acceptors) that receive the message sent by the same sender?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions