How to do Network discovery using UDP broadcast

前端 未结 5 1828
眼角桃花
眼角桃花 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 02:57

    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();
    
    0 讨论(0)
  • 2020-11-27 03:10

    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.

    0 讨论(0)
  • 2020-11-27 03:13

    For working example, see that project:https://github.com/xmegz/MndpTray

    The server periodically sends broadcast messages. The client side receive and process them. Many host information (Os version, IP address, Network interface, etc..) send trought. udp broadcast cdp lldp

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-11-27 03:24

    I had the same question but it was not that easy for me as the answer that @rufanov suggests.

    Here some situation I had:

    • Since my application is running normally in a computer that has several network interfaces, I had the problem that the broadcast message was sent only in one of the adapters. To solve this situation I had to get first all the network adapter list and go one by one sending the broadcast message and receiving the answer message.
    • It is important that you bind the correct localIpEndPoint to your adapters ip address, otherwise you will have problems with the broadcast address by sending.

    After some reserch and work I got to this solution. This code corresponds to the server side and will make the network discovery of all devices answering to the braodcast message.

    public static void SNCT_SendBroadcast(out List<MyDevice> DevicesList)
    {
      DevicesList = new List<MyDevice>();
      byte[] data = new byte[2]; //broadcast data
      data[0] = 0x0A;
      data[1] = 0x60;
    
      IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, 45000); //braodcast IP address, and corresponding port
    
      NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); //get all network interfaces of the computer
    
      foreach (NetworkInterface adapter in nics)
      {
        // Only select interfaces that are Ethernet type and support IPv4 (important to minimize waiting time)
        if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet) { continue; }
        if (adapter.Supports(NetworkInterfaceComponent.IPv4) == false) { continue; }
        try
        {
            IPInterfaceProperties adapterProperties = adapter.GetIPProperties();    
            foreach (var ua in adapterProperties.UnicastAddresses)
            {
                if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                 //SEND BROADCAST IN THE ADAPTER
                    //1) Set the socket as UDP Client
                    Socket bcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //broadcast socket
                    //2) Set socker options
                    bcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                    bcSocket.ReceiveTimeout = 200; //receive timout 200ms
                    //3) Bind to the current selected adapter
                    IPEndPoint myLocalEndPoint = new IPEndPoint(ua.Address, 45000);
                    bcSocket.Bind(myLocalEndPoint);
                    //4) Send the broadcast data
                    bcSocket.SendTo(data, ip);
    
                //RECEIVE BROADCAST IN THE ADAPTER
                    int BUFFER_SIZE_ANSWER = 1024;
                    byte[] bufferAnswer = new byte[BUFFER_SIZE_ANSWER];
                    do
                    {
                        try
                        {
                            bcSocket.Receive(bufferAnswer);
                            DevicesList.Add(GetMyDevice(bufferAnswer)); //Corresponding functions to get the devices information. Depends on the application.
                        }
                        catch { break; }
    
                    } while (bcSocket.ReceiveTimeout != 0); //fixed receive timeout for each adapter that supports our broadcast
                    bcSocket.Close();
                }
            }
          }
          catch { }
      }
      return;
    }
    
    0 讨论(0)
提交回复
热议问题