Search code examples
c#socketssynchronizationudp

Broadcast UDP message to multiple sockets listening on the same port


I'd like to sync different processes in unix environment using UDP. All the processes that need to be sync will be listening on the same port using this: How do SO_REUSEADDR and SO_REUSEPORT differ?

I tried on macOS with the following c# code without success:

using System.Net;
using System.Net.Sockets;

async Task Listen (){
    try
    {
        IPEndPoint localpt = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4000);

        UdpClient udpServer = new UdpClient();
        udpServer.ExclusiveAddressUse = false;
        udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.Client.EnableBroadcast = true;
        udpServer.Client.Bind(localpt);

        Console.WriteLine("listening");
        while (true)
        {
            var msg = await udpServer.ReceiveAsync();
            Console.WriteLine("Datagram received on UDP socket " + localpt);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}


void Send()
{
    byte[] SYNC_DATAGRAM = "SYNC"u8.ToArray();
    var client = new UdpClient();
    client.EnableBroadcast = true;
    client.Send(SYNC_DATAGRAM, SYNC_DATAGRAM.Length, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4000));
    
}

Listen();
Listen();

Thread.Sleep(1000);
Send();
Console.Read();

Only one socket receive the message and it seems that a loadbalancer is distributting the messages. How can all sockets receive the message?


Solution

  • We were in the correct direcection. Finally I made it work just sending to 255.255.255.255 and listening on ANY endpoint 0.0.0.0.

    Here is a working code in c#:

    using System.Net;
    using System.Net.Sockets;
    
    async Task Listen (int id=0){
        try
        {
            IPEndPoint localpt = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 4000);
    
            UdpClient udpServer = new UdpClient();
            udpServer.ExclusiveAddressUse = false;
            udpServer.Client.Bind(localpt);
            Console.WriteLine("listening");
            while (true)
            {
                var msg = await udpServer.ReceiveAsync();
                Console.WriteLine("Datagram received on UDP socket " + id);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
    
    
    void Send()
    {
        byte[] SYNC_DATAGRAM = "SYNC"u8.ToArray();
        var client = new UdpClient();
        client.Client.EnableBroadcast = true;
        client.Send(SYNC_DATAGRAM, SYNC_DATAGRAM.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 4000));
        
    }
    
    Task.Run(() => Listen(1));
    Task.Run(() => Listen(2));
    Task.Run(() => Listen(3));
    Task.Run(() => Listen(4));
    Task.Run(() => Listen(5));
    
    Thread.Sleep(1000);
    Send();
    Console.Read();