Network discovery using UDP Broadcast (Java)

The Problem

I have a Java server and a Java client running on the same network and the applications are not to be used outside a private network (not over internet).

So I used a static IP for the server, but what if I deploy my application? What if the network changes? That means I’ll lose my connection to the server and I’ll have to change the IP on the client side again.

Now that would be stupid. I want the client to “discover” the server on the network and connect with it.


The Solution

Using UDP packets and broadcasting them! This technique however is not optimal, but as long as we stay in one network this shouldn’t be a problem.
UDP packets however are fairly easy to work with. So let’s get started.


Still here? Let’s do this!

Server implementation

First, Let’s create the Java Singleton class that will execute the code on the server-side. This will be multi-threaded of course,  so we’ll also implement “Runnable”.

When we implement Runnable, we also have to override the Run method.

public class DiscoveryThread implements Runnable {

  @Override
  public void run() {
  }

  public static DiscoveryThread getInstance() {
    return DiscoveryThreadHolder.INSTANCE;
  }

  private static class DiscoveryThreadHolder {

    private static final DiscoveryThread INSTANCE = new DiscoveryThread();
  }

}

Ok, let’s think about this. What do we have to do?

  1. Open a socket on the server that listens to the UDP requests. (I’ve chosen 8888)
  2. Make a loop that handles the UDP requests and responses
  3. Inside the loop, check the received UPD packet to see if it’s valid
  4. Still inside the loop, send a response to the IP and Port of the received packet

That’s it on the server side.

Now, we’ll translate this into code.

DatagramSocket socket;

  @Override
  public void run() {
    try {
      //Keep a socket open to listen to all the UDP trafic that is destined for this port
      socket = new DatagramSocket(8888, InetAddress.getByName("0.0.0.0"));
      socket.setBroadcast(true);

      while (true) {
        System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!");

        //Receive a packet
        byte[] recvBuf = new byte[15000];
        DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
        socket.receive(packet);

        //Packet received
        System.out.println(getClass().getName() + ">>>Discovery packet received from: " + packet.getAddress().getHostAddress());
        System.out.println(getClass().getName() + ">>>Packet received; data: " + new String(packet.getData()));

        //See if the packet holds the right command (message)
        String message = new String(packet.getData()).trim();
        if (message.equals("DISCOVER_FUIFSERVER_REQUEST")) {
          byte[] sendData = "DISCOVER_FUIFSERVER_RESPONSE".getBytes();

          //Send a response
          DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), packet.getPort());
          socket.send(sendPacket);

          System.out.println(getClass().getName() + ">>>Sent packet to: " + sendPacket.getAddress().getHostAddress());
        }
      }
    } catch (IOException ex) {
      Logger.getLogger(DiscoveryThread.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

A few notes; If you want to use strings as commands (like I do in this example), you have to trim the string before comparing it.

There, that’s it for the server.

Client implementation

Now we have to write the code for the client. Again, let me sketch how we are going to work.

  1. Open a socket on a random port.
  2. Try to broadcast to the default broadcast address (255.255.255.255)
  3. Loop over all the computer’s network interfaces and get their broadcast addresses
  4. Send the UDP packet inside the loop to the interface’s broadcast address
  5. Wait for a reply
  6. When we have a reply, check to see if the package is valid
  7. When it’s valid, get the package’s sender IP address; this is the server’s IP address
  8. CLOSE the socket! We don’t want to leave open random ports on someone else’s computer

On a side note, we don’t close the socket on the server because the server will receive and send UPD packets until the server is closed. Closing the socket on the server means that we won’t be able to discover it any more.

Wow, that was quite a lot. Now let’s put this into code!

        // Find the server using UDP broadcast
        try {
          //Open a random port to send the package
          c = new DatagramSocket();
          c.setBroadcast(true);

          byte[] sendData = "DISCOVER_FUIFSERVER_REQUEST".getBytes();

          //Try the 255.255.255.255 first
          try {
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), 8888);
            c.send(sendPacket);
            System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
          } catch (Exception e) {
          }

          // Broadcast the message over all the network interfaces
          Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
          while (interfaces.hasMoreElements()) {
            NetworkInterface networkInterface = interfaces.nextElement();

            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
              continue; // Don't want to broadcast to the loopback interface
            }

            for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
              InetAddress broadcast = interfaceAddress.getBroadcast();
              if (broadcast == null) {
                continue;
              }

              // Send the broadcast package!
              try {
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, 8888);
                c.send(sendPacket);
              } catch (Exception e) {
              }

              System.out.println(getClass().getName() + ">>> Request packet sent to: " + broadcast.getHostAddress() + "; Interface: " + networkInterface.getDisplayName());
            }
          }

          System.out.println(getClass().getName() + ">>> Done looping over all network interfaces. Now waiting for a reply!");

          //Wait for a response
          byte[] recvBuf = new byte[15000];
          DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
          c.receive(receivePacket);

          //We have a response
          System.out.println(getClass().getName() + ">>> Broadcast response from server: " + receivePacket.getAddress().getHostAddress());

          //Check if the message is correct
          String message = new String(receivePacket.getData()).trim();
          if (message.equals("DISCOVER_FUIFSERVER_RESPONSE")) {
            //DO SOMETHING WITH THE SERVER'S IP (for example, store it in your controller)
            Controller_Base.setServerIp(receivePacket.getAddress());
          }

          //Close the port!
          c.close();
        } catch (IOException ex) {
          Logger.getLogger(LoginWindow.class.getName()).log(Level.SEVERE, null, ex);
        }

There, that’s it!

I’ve given you pretty much all of the code, so it shouldn’t be easy to implement.

Don’t forget to run your DiscoveryThread!

Thread discoveryThread = new Thread(DiscoveryThread.getInstance());
    discoveryThread.start();

~Michiel De Mey 

Michiel De Mey

Full-time geek, Full Stack Engineer and Full Metal Hero. NodeJs, AngularJs, API design, WebSockets, WebSec & IoT enthusiast. Former San Francisco resident.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus

  • quax

    Nice work! Thanks, saved me e lot of brain power 😀

  • Nice, this is so helpful for me. You are smart!

  • Mathias Nielsen

    Awesome!!! Been searching a lot on stackoverflow, to try to find a nice example of broadcasting and receiving. This is just what i needed. Thanks! 🙂

  • Ricardo

    could you share your project? Thanks for this article!

    • I’m sorry, but it was a crappy school assignment and I dare not share such a mediocre project. 🙂

      • prasad davili

        Thanks for this article,It was good but i want know how to send a KeepAlive packets from client to server for every two sec
        could you please tell me in this problem

  • Thanks alot for sharing

  • Nitesh

    Tres Bien

  • jarok

    hi. good day to you sir i would like to ask if your code are working properly because I would like to ask your permission to use your code becasue I want to use your code as an example for our thesis…
    please send me if you agree in my e-mail: [email protected]

  • FX ROBIN

    Really great article with a great sense of teaching !

  • Ansh

    I had a query as to if we use Socket Programming for an application deployed over the internet, is it feasible or even remotely possible?

    • It depends on what your needs are.
      Personally, I dislike the idea of opening a socket connection over the internet because there might be some serious security issues if you don’t know what you are doing.

      But when you’re programming for example a game, then you need a socket connection over the internet to leverage the real-time capabilities.

      If you’re just programming a simple server that does some Database queries once in a while, you might want to build a RESTful API over HTTP.

      Or if you want some sort of hybrid solution, you can look into WebSockets.

  • cybersa

    Thanks bro.
    Nice reference.Found solution for my program.

  • LucasM

    Thanks a lot! One small thing: you should set the socket port on client side in order to be able to receive packets from server since it sends datagram packets to the host to a fixed port. Cheers!

    • LucasM

      Hmmm forget it. It works like a charm 🙂

  • Daniele will love you forever

    OMG You made my day

    😀

  • Unknown

    You are awesomeB-)

  • Mahmood

    thanks a lot dud … What if we make the client to try to connect to all IPs then we handle the exception . If there is an exception, just avoid .

  • Judd

    What happens if the server does not respond? Also, are there any local machine issues that might stop the packets from getting to the server? (Happens to be something I am running into at the moment).

  • johny

    Hello Michiel!! What Happens if therer are multiple servers and I want to get list of IP’s of allthe servers.Your code currently checks response from single server..How to modify it to take response from multiple servers?

    • Sphinx111

      I would suggest that at the end of the client discover thread, you don’t close the port, and put the main body of the loop (receiving and handling packets) in a while {} loop. Then, for each response received, send the address to a List of some sort.

      Once you have “enough” servers, or the loop has run for a certain amount of time, you can terminate the loop and close the socket.

  • Santhosh

    Nice, this is helpful.
    But i have one question
    I have server which can send UDP that can send UDP packets, client needs to read udp packets and figure out the server ip.
    I need to implement client on android and IOS, so thought of developing hybrid approach with web sockets, but looks like web sockets works on TCP.
    Can you please suggest what will be best approach to discover server in hybrid approach

    • Ram Prasad

      Hi Santhosh …Can you please drop ur mail or contact . becoz even I also have same requirement in my project can we discuss on this topic ?? My mail: [email protected]

  • rowifi

    This works for me, but I am struggling to get a received message passed back to the UI thread. ( Newbie) and I’m coming across all sorts of errors and warnings.
    I know I need to use handlers, but really could do with a simple piece of working code that doesn’t give ‘ handler must be static’ or ‘Static method cannot access instance members’ etc.
    So under the bit ‘ Send a response’ needs to send the UDP message to my Start Activity.
    Help accepted…

  • Nice article. Typo: `I’ve given you pretty much all of the code, so it shouldn’t be easy to implement.` Either /shouldn’t/should/ or /easy/hard/. Also on demey.io.

  • tesfaye gec

    great! it is help full dude!

  • Erik

    Thank you for this article. It helps me alot to get into Java network stuff.

  • Arif Siddiqui

    Thank You very much Sir

    • Nil Somudro

      Hi. Can you give me the source code of this project you have implemented ? I can’t understand the client part..there’s lots of error and unknown variables

  • Nil Somudro

    Hello Michiel De Mey,
    I can not run the program. In client section there’s is lots of errors..No variable type declared for “c” , getClass() static function can not be called, and mostly Controler_Base and Logger , is unrecognized..can you please give me any solution? i urgently need it.thanks

  • Safa abdul karim

    simply awesome. i was unable to fix the port of server. it was dynamic by-default. but your code helped me to fix the port of server (Y)
    Thank you so much.

  • Juliy Kerpan

    Great article!!! You made my day!