1

I'm creating a C# socket for UDP receive and send capabilities with Asynchronous callback functions for the receive. Simple, right! It took a while to get all the wrinkles ironed out, but it works... Well, as long as you hog the port! I need to allow other applications to use the same port number. No problem, right! There's an option for that, SetSocketOption(...) for ReuseAddress...

udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);

Why is it that when I set ReuseAddress to true, the callback function doesn't get hit anymore?

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CSharpUtilityLibrary.Utilities;

namespace CSharpNIU.Sockets
{
      public class PacketEventArgs : EventArgs {
      public byte[] Bytes { get; set; }
      public PacketEventArgs(byte[] bytes)
      {
         Bytes = bytes;
      }
   }

   public delegate void PacketEventHandler(object sender, PacketEventArgs e);

   // State object for reading client data asynchronously
   public class StateObject
   {
      // Client  socket.
      public Socket workSocket = null;

      // Size of receive buffer.
      public const int BufferSize = 1553;

      // Receive buffer.
      public byte[] buffer = new byte[BufferSize];
   }

   public class UDPSocket
   {
      // Thread signal.
      public ManualResetEvent allDone = new ManualResetEvent(false);

      public String ApplicationName { get; set; }
      public Form ParentForm { get; set; }
      public Network ApplicationNetwork { get; set; }
      private ConfigGeneric Config { get; set; }
      private Socket udpClient = null;

      public UDPSocket(ConfigGeneric config, String applicationName)
      {
         Config = config;

         ApplicationDetails appDetails = config.GetApplicationByName(applicationName);
         if (appDetails == null)
            return;

         ApplicationNetwork = config.GetNetworkByName(appDetails._network);
         if (ApplicationNetwork == null) return;
      }

      public void StartListening()
      {
         // Data buffer for incoming data.
         byte[] bytes = new Byte[1024];

         IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._networkAddress);
         IPEndPoint localEndPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);

         // Create a UDP Socket
         udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

         // Bind the socket to the local endpoint
         try
         {
            // Set the event to nonsignaled state.
            allDone.Reset();

            // Start an asynchronous socket to listen for connections.
            allDone.Set();
            StateObject stateObject = new StateObject();
            stateObject.workSocket = udpClient;
//------> The line Below causes the begin receive to not call ReadCallback <-------//
            udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
//------> The line Above causes the begin receive to not call ReadCallback <-------//
            udpClient.Bind(localEndPoint);

            udpClient.BeginReceive(stateObject.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), stateObject);

            // Wait until a connection is made before continuing.
            allDone.WaitOne();
         }
         catch (Exception e)
         {
            Console.WriteLine(e.ToString());
         }
      }

      public void ReadCallback(IAsyncResult ar)
      {
         String content = String.Empty;

         // Retrieve the state object and the handler socket from the asynchronous state object.
         StateObject state = (StateObject)ar.AsyncState;
         Socket handler = state.workSocket;

         // Read data from the client socket. 
         int bytesRead = handler.EndReceive(ar);

         if (bytesRead > 0)
         {
            PacketEventArgs packetEventArgs = new PacketEventArgs(state.buffer);
            OnRecevedPacket(packetEventArgs);

            // There  might be more data, so store the data received so far.
            udpClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), state);
         }
      }

      // Event Handlers
      public event PacketEventHandler ReceiveCallback;

      protected virtual void OnRecevedPacket(PacketEventArgs e)
      {
         if (ReceiveCallback != null)
            ReceiveCallback(this, e);
      }

      public void Send(byte[] bytes)
      {
         // Begin sending the data to the remote device.
         IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._broadcastAddress);
         IPEndPoint endPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);

         udpClient.SendTo(bytes, endPoint);
      }
   }
}
Dainon
  • 23
  • 3
  • *Update* I just noticed that the SetSocketOption throws an exception of 'Invalid argument was supplied', which prevents the BeginReceive from getting called. I have more to investigate. – Dainon Sep 26 '13 at 19:48
  • I haven't found anything that says what makes that line have an invalid argument. I did notice some posts where people were using UdpClient and setting the socket option with SocketOptionLevel.Socket. That gets rid of the exception, but there still isn't a callback to the ReadCallback function. – Dainon Sep 26 '13 at 21:56

1 Answers1

0

From what I can tell, you should be using UdpClient instead of going low level with Socket.

You also need to create UdpClient with the default constructor to be able to change settings like ExclusiveAddressUse.

This guy has a working example: http://social.msdn.microsoft.com/Forums/en-US/fe830c54-30ab-4ae6-a86a-7c2a9ccd11cf/udpclient-more-than-one-on-the-same-port