0

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?

Daniel Argüelles
  • 2,229
  • 1
  • 33
  • 56
  • Try sending on Machine IP address and listen on loopback address 127.0.0.1. – jdweng Apr 07 '23 at 15:46
  • It doesn't work. In fact, 0 messages arrived – Daniel Argüelles Apr 07 '23 at 15:59
  • That doesn't sound right. You should be able to send to the IP address. There may be something wrong with your Network – jdweng Apr 07 '23 at 18:20
  • The SO_ approach lets you bind multiple sockets to the same port, but you're sending a single packet to a single address/port (unicast), so only one of them will get it. You need to use multicast instead. – Stephen Cleary Apr 08 '23 at 00:15
  • Looks like you also need `SO_REUSEPORT` so add `udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)15, true);` – Charlieface Apr 09 '23 at 20:03
  • Also you are not awaiting the result of `Listen`, you should do `Task.Run(Listen);` or similar – Charlieface Apr 09 '23 at 20:04

1 Answers1

1

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();

Daniel Argüelles
  • 2,229
  • 1
  • 33
  • 56
  • 1
    `IPAddress.Any` and `IPAddress.Broadcast` are simpler to use, they don't require `.Parse`. You can also create the `UdpClient` using the constructor and it will bind automatically `new UdpClient(new IPEndPoint(IPAddress.Any, 4000))` – Charlieface Apr 16 '23 at 16:11
  • That's right about `.Parse`, however constructor is mandatory because `ExclusiveAddressUse` needs to be set before bind – Daniel Argüelles Apr 17 '23 at 15:54