title: UDP Multicast between two sockets in the same process
body: <p>I'm writting some tests for classes that handles UDP multicast communication.
  I designed the tests to use the loopback interface (127.0.0.1) for the tests because I don't want the them to interfer with other programs/devices on the network.</p>
  
  <p>In my "unit test" I have a tested socket that joins a given multicast group and binds to 127.0.0.1 and a sender
  socket that also joined the same multicast group and binds to 127.0.0.1, both of course in the same process.</p>
  
  <p>To be sure that the message is sent I have another test program (so another process) that also joins the multicast group and outputs everything that is sent to it.</p>
  
  <p>The problem is that my tested socket never receive what the sender sent BUT the test program (so another process) receives it.</p>
  
  <p>Are there some limitation with the combination multiple sockets/multicast/localhost?</p>
  
  <p>New information:</p>
  
  <p>My mistake was to consider that UDP on localhost <em>might</em> be reliable. The below test program shows that the first UDP packet is never received (at least on my computer) by my listening socket (but the other process still receives it).</p>
  
  <p>In my unit tests I am sending one packet and expects specific answers: I cannot afford sending the message two times and receiving the answer only once.</p>
  
  <p>It seems to work reliably if I wait for the first receive timeout to occur before sending the first packet.</p>
  
  <p>Does anyone have an idea why the first UDP packet never arrives?</p>
  
  <p>Here's the code I used in my trials:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Net;
  using System.Net.Sockets;
  using System.Threading;
  using NUnit.Framework;
  
  namespace MulticastTest
  {
      [TestFixture]
      public class Program
      {
          static void Main(string[] args)
          {
              new Program().Run();
              Console.WriteLine("Press any key to exit...");
              Console.ReadKey();
          }
  
      [Test]
      public void Run()
      {
          _waitFirstReadTiemout = new AutoResetEvent(false);
          IPAddress lMulticastAddress = new IPAddress(0xFAFFFFEF);
          IPEndPoint lRemoteEndPoint = new IPEndPoint(lMulticastAddress, 1900);
  
          // Create sender socket
          Socket lSendSocket = new Socket(AddressFamily.InterNetwork,
                               SocketType.Dgram,
                               ProtocolType.Udp);
  
          // Allow to share the port 1900 with other applications
          lSendSocket.SetSocketOption(SocketOptionLevel.Socket,
                                  SocketOptionName.ReuseAddress,
                                  true);
  
          // Set TTL for multicast packets: socket needs to be bounded to do this
          lSendSocket.SetSocketOption(SocketOptionLevel.IP,
                                  SocketOptionName.MulticastTimeToLive,
                                  2);
  
          // Bind the socket to the local end point: this MUST be done before joining the multicast group
          lSendSocket.Bind(new IPEndPoint(IPAddress.Loopback, 55236));
  
          // Join the multicast group
          lSendSocket.SetSocketOption(SocketOptionLevel.IP,
                          SocketOptionName.MulticastLoopback,
                          true);
  
          lSendSocket.SetSocketOption(SocketOptionLevel.IP,
                                  SocketOptionName.AddMembership,
                                  new MulticastOption(lMulticastAddress));
  
          // Create receiver and start its thread
          Thread lReceiveThread = new Thread(ReceiveThread);
          lReceiveThread.Start();
  
          int i = 0;
          while (!fStop)
          {
              if (i == 0)
                  _waitFirstReadTiemout.WaitOne(10000);
  
              byte[] lToSend = Encoding.ASCII.GetBytes(DateTime.Now.ToString("yyyyMMdd HHmmss"));
              lSendSocket.SendTo(lToSend, lRemoteEndPoint);
              Console.WriteLine("Sent #" + (i + 1) + ": " + DateTime.Now.ToString("yyyyMMdd HHmmss"));
              Thread.Sleep(1000);
              try
              {
                  if (Console.KeyAvailable || i &gt;= 10)
                      fStop = true;
              }
              catch (InvalidOperationException)
              {
                  fStop = i &gt;= 10;
              }
              finally
              {
                  ++i;
              }
          }
      }
  
      private AutoResetEvent _waitFirstReadTiemout;
  
      private bool fStop;
  
      private void ReceiveThread()
      {
          Socket lSocket = new Socket(AddressFamily.InterNetwork, 
                                      SocketType.Dgram, 
                                      ProtocolType.Udp);
  
          // Allow to share the port 1900 with other applications
          lSocket.SetSocketOption(SocketOptionLevel.Socket,
                                  SocketOptionName.ReuseAddress,
                                  true);
  
          // TTL not required here: we will only LISTEN on the multicast socket
          // Bind the socket to the local end point: this MUST be done before joining the multicast group
          lSocket.Bind(new IPEndPoint(IPAddress.Loopback, 1900));
  
          // Join the multicast group
  
          // If the local IP is a loopback one, enable multicast loopback
          lSocket.SetSocketOption(SocketOptionLevel.IP,
                      SocketOptionName.MulticastLoopback,
                      true);
  
          lSocket.SetSocketOption(SocketOptionLevel.IP,
                                  SocketOptionName.AddMembership,
                                  new MulticastOption(
                                          new IPAddress(0xFAFFFFEF)));
  
          lSocket.ReceiveTimeout = 1000;
  
          byte[] lBuffer = new byte[65000];
          int i = 0;
          while (!fStop)
          {
              try
              {
                  int lReceived = lSocket.Receive(lBuffer);
                  ++i;
                  Console.WriteLine("Received #" + i + ": " + Encoding.ASCII.GetString(lBuffer, 0, lReceived));
              }
              catch (SocketException se)
              {
                  _waitFirstReadTiemout.Set();
                  Console.WriteLine(se.ToString());
              }
          }
      }
  }
  </code></pre>
  
  <p>}</p>