2

In a project there is a device that listens on a specific UDP port and answers to the senders port.

For the sender and receiver I want the system to choose a free port, so I have the following code:

[Please excuse the vast masses of code, but this is the smallest example to show what behaviour occurs]

Sending code:

public class UdpSender
{
    public int Port = 0; // some initially random port
    public UdpClient UdpServer { get; set; }

    public UdpSender()
    {
        UdpServer = CreateUdpClient();

        // save the portnumber chosen by system to reuse it
        Port = ((IPEndPoint)(UdpServer.Client.LocalEndPoint)).Port;
    }

    private UdpClient CreateUdpClient()
    {
        if (UdpServer != null)
        {
            UdpServer.Close();
        }

        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Port);

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

        return udpServer;
    }

    public void Send(byte[] arr)
    {
        UdpServer = CreateUdpClient();

        int remotePortNumber = 6565;
        var remoteEndPoint = new IPEndPoint(IPAddress.Broadcast, remotePortNumber);

        try
        {
            UdpServer.Send(arr, arr.Length, remoteEndPoint);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        UdpServer.Close();
    }
}

Receiving code:

public class UDPListener
{
    private static int portNumber;
    private UdpClient udpClient = null;
    public List<DeviceData> DeviceList = new List<DeviceData>();

    public UDPListener(int port)
    {
        portNumber = port;
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, portNumber);

        udpClient = new UdpClient();
        udpClient.ExclusiveAddressUse = false;

        udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpClient.Client.Bind(localEndPoint);
        udpClient.Client.ReceiveBufferSize = 1 << 23;
    }

    public void StartListening()
    {
        this.udpClient.BeginReceive(Receive, new object());
    }

    private void Receive(IAsyncResult ar)
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Any, portNumber);
        byte[] bytes = udpClient.EndReceive(ar, ref ip);
        string message = Encoding.ASCII.GetString(bytes);
        DeviceList.Add(new DeviceData(message));
        StartListening();
    }
}

Bringing it together:

public class DeviceFinder
{
    public IEnumerable<DeviceData> Find()
    {
        var sender = new UdpSender();
        int port = sender.Port;

        var listener = new UDPListener(port);
        listener.StartListening();

        sender.Send(new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });

        System.Threading.Thread.Sleep(5000); // wait some time for answers

        return listener.DeviceList;
    }
}

The Receive method is never called with this approach. But in Wireshark, I can see an answer coming from the device.

What is wrong about this approach?

Before using this approach, I have used a fixed port and the call to CreateUdpClient was added also. Seems to have something to with that, but I cannot figure it out. Before I just created a UdpClient with the fixed port just inside the receive / send method.

The previous version can be seen in this question. This works perfectly. But I fear if the fixed port is already in use, it does not work, hence this new approach.

Community
  • 1
  • 1
Mare Infinitus
  • 8,024
  • 8
  • 64
  • 113
  • Looks like you're still using a hard coded port when sending (`int remotePortNumber = 6565;`) – nos Aug 11 '14 at 12:58
  • this is the port the device is listening on. So I send to 6565 from port 11111 (for example) and the device will answer to port 11111. – Mare Infinitus Aug 11 '14 at 12:59

1 Answers1

3

Just specify zero as your own port number. The system will allocate one when you bind or send. The source port number will accompany the datagram to the peer, who should reply to it.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • This is exactly what I do. And I want to use this port allocated by the system in both sender and receiver. But the Receive method does not get called. – Mare Infinitus Aug 12 '14 at 05:45
  • So call it. Is that what you really meant to say? – user207421 Aug 12 '14 at 10:54
  • At the moment, I do not really understand I believe. As given in the example code in the question, the first time called the local-endpoints port is set to zero (0). So the system will allocate a free port for me. Now I want to use that port for both sender and receiver. And, with the approach in the question, the Receive method is never called, which should be done by the system when an incoming udp datagram is received for that port. This is the part that does not work. What do mean with "So call it"? – Mare Infinitus Aug 12 '14 at 11:06