How to do Network discovery using UDP broadcast

I want to to do network discovery using UDP Broadcast in C#. I don't know how to do this. Can you give me advice on how to do it?

I want to do like this tutorial.


It's very simple to make same thing in C#

Server:

var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");

while (true)
{
    var ClientEp = new IPEndPoint(IPAddress.Any, 0);
    var ClientRequestData = Server.Receive(ref ClientEp);
    var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);

    Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
    Server.Send(ResponseData, ResponseData.Length, ClientEp);
}

Client:

var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);

Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));

var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());

Client.Close();

Here is a different solution that is serverless. I had a need to have a bunch of raspberry pis be aware of each other on a network, but had no guarantees of who would be active. So this approach allows everyone to be a client! The complete library is available on GitHub (disclaimer: I created) and that makes this whole process really reaaaally easy for UWP apps.

https://github.com/mattwood2855/WindowsIotDiscovery

This solution assumes that device names are unique and that you want to use JSON strings as the communication protocol, but you could easily just send any other format. Also, in practice try-catch everything ;)

The general mechanism:

Discover your IpAdress

public string IpAddress
{
    get
    {
        var hosts = NetworkInformation.GetHostNames();
        foreach (var host in hosts)
        {
            if (host.Type == HostNameType.Ipv4) return host.DisplayName;    
        }
        return "";
    }
}

Set up your listener

var udpPort = "1234";
var socket = new DatagramSocket();
socket.MessageReceived += ReceivedDiscoveryMessage;
await socket.BindServiceNameAsync(udpPort);`

Handle incoming data

async void ReceivedDiscoveryMessage(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs args)
{
    // Get the data from the packet
    var result = args.GetDataStream();
    var resultStream = result.AsStreamForRead();
    using (var reader = new StreamReader(resultStream))
    {
        // Load the raw data into a response object
        var potentialRequestString = await reader.ReadToEndAsync(); 
        // Ignore messages from yourself
        if (args.RemoteAddress.DisplayName == IpAddress) return;        
        // Get the message
        JObject jRequest = JObject.Parse(potentialRequestString);
        // Do stuff with the data
    }
}

Send a message

public async void SendDataMessage(string discoveryMessage)
{
    // Get an output stream to all IPs on the given port
    using (var stream = await socket.GetOutputStreamAsync(new HostName("255.255.255.255"), udpPort))
    {
        // Get a data writing stream
        using (var writer = new DataWriter(stream))
        {
            // Write the string to the stream
            writer.WriteString(discoveryMessage);
            // Commit
            await writer.StoreAsync();
        }
    }
}

The idea would be to send a discovery message containing your ip address and name. Then in the receive message function add the ip-name pairs to a List of devices. Add a little logic to avoid duplicates and update Ip address if the ip changes for a given name.

As a bonus, you can have each device send the list of devices they know about. This allows you to minimize udp traffic by not responding when the sender is aware of you. You can even have the receiver compare the list against their own list to discover other devices.

Redundancy is your friend with UDP, there is no guarantee that a packet will be delivered.


I know it's old but someone may still need this...The accepted answer is great but with this little tweak on the server side it's even better.

Fix for the Ilya Suzdalnitski comment (locks up on the second Client.Receive call):

var responseData = Encoding.ASCII.GetBytes("someData");     
while (true)
{
    var server = new UdpClient(8888);
    var clientEp = new IPEndPoint(IPAddress.Any, 0);
    var clientRequestData = server.Receive(ref clientEp);
    var clientRequest = Encoding.ASCII.GetString(clientRequestData);

    Console.WriteLine($"Recived {clientRequest} from {clientEp.Address}, sending 
    response: {responseData}");
    server.Send(responseData, responseData.Length, clientEp);
    server.Close();
}

Because after each response the server is closed and recreated, it can work endlessly without locking.