Question

I'm trying to receive data via an UdpSocket from a multicast address. The Socket doesn't receive data, before I sent data over the socket. After sending, i can receive a few packages, and then i have to send again, before I can receive more packages. Packages meanwhile sent from other hosts are lost. I think, it isn't a firewall issue like here: C# UDP Socket doesn't receive data until after data is sent because whireshark receives all packages. Can somebody explain me this behavior?

class Program
{
    private static UdpClient _mdnsSocket;
    private static IPEndPoint _mdnsGroup;
    private static IPEndPoint _localEp;

    static void Main(string[] args)
    {
        var interfaces = NetworkInterface.GetAllNetworkInterfaces()
                                         .Where(i => i.OperationalStatus == OperationalStatus.Up)
                                         .ToArray();

        for (int i = 0; i < interfaces.Length; ++i)
        {
            var interf = interfaces[i];
            Console.WriteLine("{0}) Name: {1}", i, interf.Name);
        }
        Console.WriteLine();

        do
        {
            int i;
            Console.Write("Interface: ");
            var line = Console.ReadLine();
            if (int.TryParse(line, out i) && i < interfaces.Length)
            {
                var addr = interfaces[i].GetIPProperties()
                                        .UnicastAddresses.FirstOrDefault(a => a.Address.AddressFamily == AddressFamily.InterNetwork);
                if (addr != null)
                {
                    _localEp = new IPEndPoint(addr.Address, 5353);
                    Console.WriteLine("Choosen IP: {0}", _localEp);
                }
            }
        } while (_localEp == null);


        _mdnsGroup = new IPEndPoint(IPAddress.Parse("224.0.0.251"), 5353);
        _mdnsSocket = new UdpClient();
        _mdnsSocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        _mdnsSocket.ExclusiveAddressUse = false;
        _mdnsSocket.Client.Bind(_localEp);
        _mdnsSocket.JoinMulticastGroup(_mdnsGroup.Address, _localEp.Address);
        BeginReceive();

        Console.WriteLine("1 to switch to multicast mode (default)");
        Console.WriteLine("2 to switch to unicast mode");
        Console.WriteLine("s for sending a message");
        Console.WriteLine("ESC for exit");

        ConsoleKey key;
        IPEndPoint ip = _mdnsGroup;
        IPEndPoint unicastip = null;
        var mode = "multicast";

        do
        {
            Console.Write("1/2/s/ESC: ");
            key = Console.ReadKey().Key;
            Console.WriteLine();

            switch (key)
            {
                case ConsoleKey.D1:
                    ip = _mdnsGroup;
                    Console.WriteLine("Switched to multicast mode");
                    mode = "multicast";
                    break;

                case ConsoleKey.D2:
                    Console.Write("Enter new IP (leave empty to use {0}):", unicastip);
                    var input = Console.ReadLine();
                    if (string.IsNullOrEmpty(input))
                    {
                        if (unicastip == null)
                        {
                            Console.WriteLine("error: no last ip!");
                            break;
                        }
                        ip = unicastip;
                        Console.WriteLine("Switched to unicast mode");
                        mode = "unicast";
                    }
                    else
                    {
                        unicastip = new IPEndPoint(IPAddress.Parse(input), 5353);
                        ip = unicastip;
                        Console.WriteLine("Switched to unicast mode");
                        mode = "unicast";
                    }
                    break;

                case ConsoleKey.S:
                    var msg = string.Format("Hello from PC via {0}", mode);
                    var bytes = Encoding.ASCII.GetBytes(msg);

                    Console.WriteLine("Sending to {0}", ip);
                    _mdnsSocket.Send(bytes, bytes.Length, ip);
                    break;
            }
        } while (key != ConsoleKey.Escape);
        _mdnsSocket.Close();
    }

    private static void BeginReceive()
    {
        Console.WriteLine("BeginReceive");
        _mdnsSocket.BeginReceive(ReceiveCallback, _mdnsSocket);
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {            
        try
        {
            var ep = new IPEndPoint(IPAddress.Any, _mdnsGroup.Port);
            var data = _mdnsSocket.EndReceive(ar, ref ep);

            var message = Encoding.ASCII.GetString(data);
            Console.WriteLine(message);
        }
        finally
        {
            BeginReceive();
        }
    }
}
Was it helpful?

Solution

After all it seems it was a firewall issue. When I allow incoming UPD on Port 5353 explicitly, it's working (Why ever allowing all incoming UPD Traffic for the respective program doesn't work). I now explain the behavior described in the question with the so called hole punching mechanism. Please correct me when I'm wrong.

OTHER TIPS

Same problem here, but firewall didn't fixed it. I'm using Windows 10 PRO.

There is another undesired effect I have found: broadcasted messages are not being received, but straight IP messages are.

The only workaround I've found was to add a timer that sends an empty byte array in broadcast every 10 seconds, so the communication is maintained well enough. The problem is that there are always useless messages transferred to the network, not so heavy, but far from optimal.

Closing the socket and starting again fixes also the problem, but it's slower, and forces the GC to run.

I'm using the same UDP class on Unity (Mono) and Visual Studio applications, but this "effect" only happens under Unity applications. This only happens on IPV4 sockets, IPV6 sockets seems to never stop listening.

I'm sure this is some kind of "Stop using IPV4 broadcast" feature in new OS's, because Windows 7 works just fine.

Hope it helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top