Search code examples
c#socketsudpbroadcast

Sending UDP Broadcast for populating USR-TCP232 LAN Modules information


I am using USR-TCP232 LAN Modules for an embedded project. I have a tool to query those modules made by the manufacturer, it works great. But, I want it in my code in C#. So, I decided to make one for myself. I believe I am so close but I guess a small glitch which gives me hard times and I need somebody to put some shed light on.

I can send a UDP broadcast and I can observe the traffic via "WireShark". It is quite similar with the original tool. But, I can't receive the answered data sent by the devices on the network in my code.

Console application in C#

using System;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;

namespace UDPer
{
    class Program
    {
        static void Main(string[] args)
        {
            UDPer udp = new UDPer();
            udp.Starter();

            ConsoleKeyInfo cki;
            do
            {
                if (Console.KeyAvailable)
                {
                    cki = Console.ReadKey(true);
                    switch (cki.KeyChar)
                    {
                        case 's':
                            udp.Send("0123456789012345678901234567890123456789");

                            break;
                        case 'x':
                            udp.Stop();
                            return;
                    }
                }
                Thread.Sleep(10);
            } while (true);
        }
    }

    class UDPer
    {
        private Socket udpSock;
        private byte[] buffer;
        public void Starter()
        {
            //Setup the socket and message buffer
            udpSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpSock.Bind(new IPEndPoint(IPAddress.Any, 0));
            udpSock.EnableBroadcast = true;
            buffer = new byte[1024];

             udpSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            //udpSock.ExclusiveAddressUse = false; // only if you want to send/receive on same machine.

             //The socket must not be bound or connected.
            //Start listening for a new message.
            EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
            udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);
        }

        public void Stop()
        {
            try
            {
                udpSock.Close();
                Console.WriteLine("Stopped listening");
            }
            catch { /* don't care */ }

        }
        private void DoReceiveFrom(IAsyncResult iar)
        {
            try
            {
                //Get the received message.
                Socket recvSock = (Socket)iar.AsyncState;
                recvSock.EnableBroadcast = true;
                EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
                int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP);
                byte[] localMsg = new byte[msgLen];
                Array.Copy(buffer, localMsg, msgLen);

                //Start listening for a new message.
                EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
                udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock);

                //Handle the received message
                Console.WriteLine("Recieved {0} bytes from {1}:{2}",
                                  msgLen,
                                  ((IPEndPoint)clientEP).Address,
                                  ((IPEndPoint)clientEP).Port);
                //Do other, more interesting, things with the received message.
                string message = Encoding.ASCII.GetString(localMsg);
                Console.WriteLine("Message: {0} ", message);
            }
            catch (ObjectDisposedException)
            {
                //expected termination exception on a closed socket.
            }
        }

        public void Send(string message)
        {
            UdpClient udp = new UdpClient(1500);
            var ipEndPoint = new IPEndPoint(IPAddress.Broadcast, 1500);
            byte[] data = Encoding.ASCII.GetBytes(message);
            udp.Send(data, data.Length, ipEndPoint);
            udp.Close();
        }
    }
}

Wireshark capture

enter image description here

Note that: This Wireshark capture is exactly the same as the original tool does.

Some definitions:

My PC where C# application resides: 192.168.65.82

LAN Module IP Address: 192.168.65.8

Ports must be 1500 which is all OK.

Send payload for querying LAN Modules; "0123456789012345678901234567890123456789"

So, I have tried tons of different options one by one but no jo so far. What am I missing here?


Solution

  • A socket always has a dedicated port. Passing an IPEndPoint with port number 0 doesn't mean that you receive packets send to any port. Instead you are binding to a port assigned by the underlying service provider.

    udpSock.Bind(new IPEndPoint(IPAddress.Any, 0));
    

    If you do not care which local port is used, you can create an IPEndPoint using 0 for the port number. In this case, the service provider will assign an available port number between 1024 and 5000

    https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.bind(v=vs.110).aspx

    You need to use

    udpSock.Bind(new IPEndPoint(IPAddress.Any, 1500));