Service Discovery within LAN

itzmeanjan

Anjan Roy

Posted on April 29, 2019

Service Discovery within LAN

idea

Let's assume a situation -- You've two devices within same Local Area Network and you want to send a file from deviceA to deviceB.

    deviceA -> deviceB
Enter fullscreen mode Exit fullscreen mode

What do you do then ?

Write a server program for deviceA and one client program for deviceB 🤔.

Well this works. But next time when you run these programs, deviceA and deviceB may have different IP addresses or another deviceC may be interested in participating in file transfer, which might eventually lead you to manually updating PEER's IP address 😞.

How about we create an automated device discovery service ?

Sounds great 👏

So let's get to work 🏃

model

We're going to use DatagramSocket, for handling Service Advertising and Service Discovery with in LAN. Implementation will be done using Dart Language and snippets for JavaScript will be provided.

init

First we're going to write Service Advertiser i.e. a UDP server program.

Service Advertiser

Classes required for implementation of proposed functionality.

import 'dart:io' show RawDatagramSocket, RawSocketEvent, InternetAddress, Datagram;
import 'dart:convert' show utf8;
Enter fullscreen mode Exit fullscreen mode

Binding a RawDatagramSocket on InternetAddress.anyIPv4 and port 8000, so that it can listen on all interfaces on port 8000.

RawDatagramSocket.bind(InternetAddress.anyIPv4, 8000).then((datagramSocket) {
    // more code coming ...
  });
Enter fullscreen mode Exit fullscreen mode

You can see RawDatagramSocket.bind( ... ) returns a Future. We'll enable READ event listener on this socket, so that whenever any other device tries to write something on this socket, a listener will be notified.

datagramSocket.readEventsEnabled = true; // put this line within aforementioned `then()`
Enter fullscreen mode Exit fullscreen mode

Now we'll listen for READ events on this
DatagramSocket. Whenever a new READ event occurs it's fetched using DatagramSocket.receive() and other end get's notified that it has reached a valid Service Advertiser.

datagramSocket.listen((RawSocketEvent event) {
      if (event == RawSocketEvent.read) {
          // checking whether it's a read event or not
        Datagram dg = datagramSocket.receive();
        if (dg != null) {
        // notifying other end that it has reached a service advertiser
          datagramSocket.send(dg.data, dg.address, dg.port);
          print('${dg.address}:${dg.port} -- ${utf8.decode(dg.data)}');
        }
      }
    });
Enter fullscreen mode Exit fullscreen mode

PEER's IP address, port number and received data are extracted from Datagram object, received on occurance of READ event.

Received data is decoded back to String from List, using following function from utf8 module.

utf8.decode(dg.data);
Enter fullscreen mode Exit fullscreen mode

Well Service Advertiser is completed 😉.

Service Discoverer

You may have already guessed, this will be simply a UDP client.

Classes required for implementation of service discovery functionality.

import 'dart:io' show RawDatagramSocket, RawSocketEvent, InternetAddress, Datagram;
import 'dart:convert' show utf8;
Enter fullscreen mode Exit fullscreen mode

Again we need to bind a RawDatagramSocket on InternetAddress.anyIPv4 and port 0, which will return Future.

Why port 0 ? 🤔

Well specifying port number 0, lets us use OS chosen port number. In client side we're not that much interested in listening on a predefined port number 😊.

RawDatagramSocket.bind(InternetAddress.anyIPv4, 0).then((datagramSocket) {
    // more code coming ...
  });
Enter fullscreen mode Exit fullscreen mode

During Service Advertising, we were just listening for READ events on RawDatagramSocket, but now we're also going to enable broadcast, so that this socket can send a broadcast message to 255.255.255.255, which will reach all devices within LAN.

// put these two lines with in previous `then()`
datagramSocket.broadcastEnabled = true;
datagramSocket.readEventsEnabled = true;
Enter fullscreen mode Exit fullscreen mode

Time to send a message on broadcastAddress and port 8000.

datagramSocket.send("io.github.itzmeanjan.transferZ".codeUnits,
        InternetAddress("255.255.255.255"), 8000);
Enter fullscreen mode Exit fullscreen mode

Aforementioned message reaches all devices present in LAN listening for READ event on port 8000.

Why port 8000 ? 🤔

Well we're using port 8000 for Service Advertising 😉.

You may be wondering what's "io.github.itzmeanjan.transferZ".codeUnits, this returns List from String, to be sent as broadcastMessage.

Now let's put logic required for listening READ events on RawDatagramSocket. Following snippet is pretty close to the one which we used in Service Advertiser, except the fact that we don't send anything back to Service Advertiser.

datagramSocket.listen((RawSocketEvent event) {
      if (event == RawSocketEvent.read) {
        Datagram dg = datagramSocket.receive();
        if (dg != null) {
          print('${dg.address}:${dg.port} -- ${utf8.decode(dg.data)}');
          //datagramSocket.close();
          // You may consider uncommenting previous line, if you want to explore only one Service Advertiser at a time.
        }
      }
    });
Enter fullscreen mode Exit fullscreen mode

And our Service Discoverer is complete 😃.

run

Time to run it 🏃

Service Advertiser

Run it using

$ dart service_advertiser.dart
Enter fullscreen mode Exit fullscreen mode

Service Discoverer

Now run the servise discoverer using

$ dart service_discoverer.dart
Enter fullscreen mode Exit fullscreen mode

service_advertiser_and_service_discoverer_running_on_computer

Here's what happened ---

I start Service Advertiser from one terminal, another Service Advertiser from a Flutter mobile app and a Service Discoverer from another terminal on same computer. All these devices are with in same LAN.

First our Service Discoverer sends a broadcastMessage to 255.255.255.255 on port 8000, and starts listening for READ event(s) on RawDatagramSocket. Then Service Advertiser(s) receive READ event notification and responds to it. Response comes to Service Discoverer, it reads that and prints out on screen.

end

And we've successfully implemented nearby service advertising & discovery with Datagram Socket, implemented using Dart Language.

Interested in having this implementation in JavaScript ?

Check here for service_advertiser and service_discoverer.

If you are interested in learning how to use this with a flutter app, you might consider checking transferZ, an android app built with ❤️ using Flutter for sending files to devices with in LAN.

See you in next article. In the mean time you may consider following me on GitHub and Twitter.

Wrap up time ✌️.

💖 💪 🙅 🚩
itzmeanjan
Anjan Roy

Posted on April 29, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Service Discovery within LAN
javascript Service Discovery within LAN

April 29, 2019