[MUSIC PLAYING]
Hi.
My name is Trevor Johns.
I'm a Developer Programs Engineer on the Android team.
Let's take a bit to talk about how to do network service
discovery on Android.
So what is network service discovery?
So say that you have a game and you want to let friends
play with each other.
One approach is to get email addresses for everyone in the
game and use that to set up a shared room on a server
somewhere in the cloud.
It's not a bad approach, especially if you're going to
be competing with someone far away.
But if all your friends are sitting right next to, all
those email addresses are going to get a bit
inconvenient.
Wouldn't it be great if you could just find nearby users
who also happen to have your app just based on
the physical proximity?
This is where network service discovery, or NSD, comes into
the picture.
NSD lets your app find other devices on the local network
that support services you're interested in.
Those services could be physical devices like
printers, webcams, HTTP servers, and, yes, even games.
In a sense, it terms any local network into a
social network for apps.
Take this game here, which uses NSD to place everyone on
the same subnet into a virtual waiting room.
It's a quick way to form teams.
Once discovered, you'll then be able to connect directly to
any of those apps using the standard
Android networking stack.
So let's go into a bit more details about
how all this works.
And then I'll show you how to implement the code for all of
this inside of your app.
NSD is based on two protocols--
DNS-SD and multicast DNS.
The SD stands for service discovery.
Like DNS on the internet, this provides a mapping between
human friendly host names--
so, say, myphone.local--
and the IP address where that device lives.
Now normally you'd go to something like google.com.
In this case, everything is going to be ending in
something.local because it's on the local subnet.
That's how the device can distinguish between devices
advertised via multicast DNS and devices advertised using
the global DNS system.
So unlike traditional DNS, MDNS is completely
distributed, which means no central server.
Devices communicate amongst themselves to build a network
directory of services.
Since it's based on multicast, it only works between devices
on the same broadcast domain.
So such as a LAN.
It also requires the network supports multicast traffic,
which some businesses or university
networks might disable.
But it should work without problems on most home
networks, or even small business networks.
DNS-SD extends multicast DNS to provide service discovery,
listing what hosts implement specific protocols.
Many people think of DNS exclusively in the context of
mapping host names to IP addresses.
But DNS is actually general, if somewhat limited,
hierarchical database.
It can store almost any kind of data
for almost any purpose.
So service names in this case will take the form of
service.transport.local.
This is how we're mapping from a service name to what you
traditionally think of as a domain name.
So in this case, we're using myapp.tcp.
myapp is the service name.
And tcp is the network transport that we're using.
Clients can then go and query on this name to retrieve the
listing of devices supporting it.
Once a desired device is selected, the IP address, port
number, and any other necessary metadata are
requested via DNS service or SRV records.
Since we're using multicast DNS rather than the usual
internet DNS infrastructure, there's no need to go and
register these domains within any registrar or pay money.
You can just simply broadcast them to network peers as
they're needed.
Now that said, it's still a good idea to register your
service name with the IANA to prevent any name collisions.
There's a free service iana.org that
will let you do this.
Now we've gone over the protocol details, let's talk
about using the NSD APIs on Android to broadcast your
app's custom service.
The good news is you don't need to worry about most of
the protocol details since the OS takes care of almost
everything for you.
So before you start, let's say that we have our app listening
on an available port.
This is just the code that you typically use to open up a
socket on Android.
But notice that we're not explicitly
selecting a port here.
Be careful to never hardcode your port number when you're
using NSD, since other apps could be using the same port
number as your app.
Instead, we'll ask the system to give us a
random unused port.
This is OK though, because we're going to go and
advertise this to other devices so they'll be able to
discover which port you're listening on.
So, now we have a service listening for traffic on our
device, we'll want to register that on the local network.
The first thing to do is to create an NSD
service info object.
This object provides all the information that other devices
on the network will use when they're deciding whether or
not to connect to your device or not.
The service type, again, uniquely identifies the
service your phone is advertising.
So something like appname.tcp.
And you'll typically put an underscore in front of each
section as a matter of convention.
The service name uniquely identifies a particular
instance of your app.
So this is not the service type, the service name.
Now with the service name, it's usually a good idea to
use the device's Bluetooth name, just as something that's
nice and human friendly.
It should be unique.
But if not, it's not a big deal.
Android we go and append a number to the end of the name
to correct that error.
Finally, we'll set the port number that we selected above
so that other apps know which port we selected.
Calling register service, finally, will inform the OS
about the new service.
And Android will take care of broadcasting that information
out to other devices as needed.
At the end here there's a registration listener, which
is a set of call backs, like on service registered, that'll
let us know about the success or failure of this operation.
We're going to see this pattern a lot over the next
few slides.
The important thing to notice here is on service registered,
which is where our app can go and store the service name.
Even though we set this when registering, the OS might have
changed it to resolve a conflict from another device
in the network.
Remember I said that the service name
always has to be unique.
So this is your chance to go and discover if it wasn't and
update your UI if needed.
You might want to go and show the service name to the user.
Not all apps do though.
So this might or might not be of interest to you.
Now that our app is registered, let's take a look
at how to issue a query to find other devices.
Service discovery, like service
registration, has two steps--
setting up a discovery listener with the relevant
call backs and making a single asynchronous API call to
discover services.
Let's work backwards.
We'll start with the call to discover services.
Here you'll pass in the service name that you're
interested in.
So again, something like myapp.tcp.
The name of the discovery protocol to use, which is
always DNS-SD--
again, this is not the protocol of your app.
It's the service discovery protocol.
And right now Android only supports DNS-SD.
So this argument will always be protocol DNS-SD.
And finally, a discovery listener object, which is what
we'll use to get the results of this discovery process.
The listener will get a call back for each device found.
And of course there's callbacks where your app can
handle any errors found.
The important method here is on service found, which is
where we're going to find out about all the services and the
devices that we're potentially interested in and store them
in the list.
This is the list that you'll typically present to the user.
And that will let them pick which devices that they want
to connect to.
So once we know which devices we want to connect to, we call
resolve service.
This is another asynchronous call.
It's a little bit expensive.
So again, we have a listener that's going to go and get the
results of this.
And this is where we find out the IP address and port number
of the device that we want to connect to.
Once you get that information, then we're just going to go
ahead and connect to it directly
using a standard socket.
Now, before you go off and play your game, there's one
last thing you want to do.
When your application exits, it is very important to
unregister your service so that the OS will stop
advertising it to other devices.
To do this, call NSD manager's unregister service method
whenever your application's onDestroy or onPause method
gets called.
You'll also want to make sure to call stop service discovery
since the discovery process is also a bit expensive, and we
don't want to leave that running unchecked.
And that's it.
You're all set to use network service discovery to find
other copies of your app on the network.
Happy networking.