4 releases
0.1.3 | Sep 22, 2024 |
---|---|
0.1.2 | Sep 22, 2024 |
0.1.1 | Sep 22, 2024 |
0.1.0 | Sep 22, 2024 |
#1049 in Network programming
306 downloads per month
31KB
468 lines
udis
- a tiny local service discovery system
There are many service discovery options available out there, but when it comes to local service discovery we mainly reach for mDNS. In most cases this is great, but sometimes it's nice just to have a really simple solution that isn't managed by the OS in any way.
udis
(micro discovery) is a dead simple system for providing local service
discovery with minimal fuss. The main use case is:
To find servers on the local network that host a kind of service on a particular port.
To achieve this, udis
uses UDP multicast to send notifications to a
"discovery network" - basically anyone who's listening - which include some
very basic information:
- the name of the endpoint, which is just some description of the application, like "server" or "client",
- the IP address of the machine that the endpoint is hosted on
- and a list of services, where each service is either:
- one the endpoint is searching for (i.e. "I want to find a service")
- or one the endpoint is actively hosting (i.e. "I can offer you a service")
Each endpoint in the network will actively listen for notifications, and if it receives one it's interested in (e.g. a server receives a notification from a client looking for one of its services) the endpoint will re-notify the network of its presence. This means the order in which endpoints join the network doesn't matter.
Once an endpoint has found a service its interested in it's the users job to continue setting up communications, e.g. using the IP address and port number to connect their own socket.
Example usage
Create a server which hosts a "hello" service on port 4112:
let udis = udis::Udis::new("server")
.host("hello", 4112)
.expect("Kind or port already hosted by this endpoint")
.build_sync()
.expect("Failed to build udis endpoint");
And then create a client which searches for the "hello" service:
let udis = udis::Udis::new("client")
.search("hello")
.build_sync()
.expect("Failed to build udis endpoint");
let service = udis.find_service().expect("Failed to find an endpoint with the `hello` service");
// prints: Found `hello` service hosted by `server` at 192.168.0.1:4112
println!(
"Found `{}` service hosted by `{}` at {}:{}",
service.kind,
service.name,
service.addr,
service.port);
Only the client
side receives notifications of services its interested in, so
the job of opening communications goes to the side that searched for the
service, not the service hoster.
For a complete example see the examples/client.rs
and
examples/server.rs
example files.
Under the hood
Sync
Under the hood the SyncUdis
endpoint type is implemented with a background
thread that communicates to the main thread with channels.
Async
udis
supports async with the tokio
runtime, which can be enabled with the
tokio
feature. When enabled you can use the build_async
function on the
udis::builder::Builder
struct which creates a tokio task rather than a thread.
Discovery notification packets
The udis notification packet is a simple JSON one, for example a server hosting a service of the kind "hello" on port 4112 might send this packet out:
{
"name": "server",
"addr": "192.168.0.1",
"services": [
{
"Host": {
"kind": "hello",
"port": 4112
}
}
]
}
Dependencies
~1–9.5MB
~99K SLoC