How to do Network discovery using UDP broadcast

前端 未结 5 1871
眼角桃花
眼角桃花 2020-11-27 02:23

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.

5条回答
  •  南方客
    南方客 (楼主)
    2020-11-27 03:16

    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.

提交回复
热议问题