Rust异步DNS服务发现库async-dnssd的使用,支持mDNS和DNS-SD协议的高效网络设备发现
Rust异步DNS服务发现库async-dnssd的使用,支持mDNS和DNS-SD协议的高效网络设备发现
该库封装了实现dnssd
的C库,用于在局域网或广域网上发现、发布和解析网络服务。它集成到异步的tokio
框架中。
安装
在您的项目目录中运行以下Cargo命令:
cargo add async-dnssd
或者在您的Cargo.toml中添加以下行:
async-dnssd = "0.5.1"
使用示例
下面是一个完整的示例,展示如何使用async-dnssd进行mDNS服务发现:
use async_dnssd::*;
use tokio::stream::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 浏览_http._tcp服务
let mut browse = browse("_http._tcp")?;
// 处理服务发现事件
while let Some(event) = browse.next().await {
match event {
// 发现新服务
BrowseEvent::ServiceFound(service) => {
println!("Service found: {:?}", service);
// 解析服务详情
let mut resolve = resolve(service)?;
if let Some(ResolveEvent::ServiceResolved(info)) = resolve.next().await {
println!("Resolved service: {:?}", info);
// 获取服务地址
let mut query = query_record(
info.host_target().to_string(),
RecordType::A,
info.interface_index(),
)?;
if let Some(QueryRecordEvent::RecordQueryResult(r)) = query.next().await {
println!("Address: {:?}", r);
}
}
}
// 服务消失
BrowseEvent::ServiceLost(service) => {
println!("Service lost: {:?}", service);
}
// 其他事件
_ => {}
}
}
Ok(())
}
完整示例
下面是一个更完整的示例,展示如何发现和解析本地网络上的打印机服务:
use async_dnssd::*;
use tokio::stream::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("开始发现本地网络上的打印机服务...");
// 浏览_ipp._tcp服务(打印机服务)
let mut browse = browse("_ipp._tcp")?;
// 处理服务发现事件
while let Some(event) = browse.next().await {
match event {
BrowseEvent::ServiceFound(service) => {
println!("发现打印机服务: {:?}", service);
// 解析服务详情
let mut resolve = resolve(service)?;
if let Some(ResolveEvent::ServiceResolved(info)) = resolve.next().await {
println!("打印机详细信息:");
println!("名称: {}", info.fullname());
println!("主机: {}", info.host_target());
println!("端口: {}", info.port());
println!("TXT记录: {:?}", info.txt_properties());
// 查询IPv4地址
let mut query = query_record(
info.host_target().to_string(),
RecordType::A,
info.interface_index(),
)?;
if let Some(QueryRecordEvent::RecordQueryResult(r)) = query.next().await {
println!("IP地址: {:?}", r);
}
// 查询IPv6地址
let mut query_v6 = query_record(
info.host_target().to_string(),
RecordType::AAAA,
info.interface_index(),
)?;
if let Some(QueryRecordEvent::RecordQueryResult(r)) = query_v6.next().await {
println!("IPv6地址: {:?}", r);
}
}
}
BrowseEvent::ServiceLost(service) => {
println!("打印机服务离线: {:?}", service);
}
_ => {}
}
}
Ok(())
}
功能说明
- 服务浏览:使用
browse()
函数发现特定类型的服务 - 服务解析:使用
resolve()
获取服务的详细信息 - 记录查询:使用
query_record()
查询服务的地址记录
注意
- 该库需要tokio运行时支持
- 在不同的平台上可能有不同的实现(macOS使用其原生Bonjour实现)
- MIT许可证允许自由使用和修改
1 回复
Rust异步DNS服务发现库async-dnssd使用指南
简介
async-dnssd
是一个Rust实现的异步DNS服务发现库,支持mDNS(多播DNS)和DNS-SD(DNS服务发现)协议。它提供了高效的方式来发现本地网络中的设备和服务,特别适合IoT设备发现、局域网服务发现等场景。
主要特性
- 完全异步实现,基于
async/await
语法 - 支持mDNS协议
- 支持DNS-SD协议
- 跨平台支持(Windows/macOS/Linux)
- 零成本抽象,高性能实现
安装
在Cargo.toml中添加依赖:
[dependencies]
async-dnssd = "0.3"
tokio = { version = "1.0", features = ["full"] }
基本使用方法
1. 服务注册
use async_dnssd::*;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 注册一个HTTP服务
let service = RegisterService::new("_http._tcp", 8080)
.with_name("My Rust Service")
.with_txt_records(&[("path=/api", "version=1.0")])
.register()
.await?;
println!("Service registered. Press Ctrl+C to stop...");
// 保持服务运行
loop {
sleep(Duration::from_secs(1)).await;
}
// 服务会在退出时自动注销
// 也可以手动调用 service.unregister().await?;
}
2. 服务发现
use async_dnssd::*;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 浏览特定类型的服务
let browser = BrowseService::new("_http._tcp")
.browse()
.await?;
println!("Discovering HTTP services on local network...");
// 处理发现的服务
while let Some(event) = browser.next().await {
match event {
ServiceEvent::ServiceFound(service) => {
println!("Found service: {}", service.name());
// 解析服务详情
if let Ok(resolved) = service.resolve().await {
println!("Service details: {:?}", resolved);
// 获取TXT记录
if let Ok(txt) = resolved.get_txt_records().await {
println!("TXT records: {:?}", txt);
}
}
}
ServiceEvent::ServiceLost(service) => {
println!("Service lost: {}", service.name());
}
}
}
Ok(())
}
3. 主机名解析
use async_dnssd::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 解析主机名
let hostname = "my-computer.local";
if let Ok(addrs) = resolve_hostname(hostname).await {
println!("Resolved {} to: {:?}", hostname, addrs);
}
Ok(())
}
高级用法
自定义网络接口
use async_dnssd::*;
use std::net::Ipv4Addr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 指定网络接口进行服务发现
let interface = Ipv4Addr::new(192, 168, 1, 10);
let browser = BrowseService::new("_http._tcp")
.on_interface(interface)
.browse()
.await?;
// ...处理发现的服务
Ok(())
}
组合查询
use async_dnssd::*;
use futures::stream::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 同时发现多种服务类型
let http_browser = BrowseService::new("_http._tcp").browse().await?;
let printer_browser = BrowseService::new("_printer._tcp").browse().await?;
let mut combined = futures::stream::select(http_browser, printer_browser);
while let Some(event) = combined.next().await {
match event {
ServiceEvent::ServiceFound(service) => {
println!("Found service: {}", service.name());
}
ServiceEvent::ServiceLost(service) => {
println!("Service lost: {}", service.name());
}
}
}
Ok(())
}
完整示例代码
下面是一个完整的服务注册和发现的示例:
use async_dnssd::*;
use tokio::time::{sleep, Duration};
use futures::stream::StreamExt;
// 服务注册示例
async fn register_service() -> Result<(), Box<dyn std::error::Error>> {
// 注册HTTP服务
let service = RegisterService::new("_http._tcp", 8080)
.with_name("Rust Test Service")
.with_txt_records(&[("path=/test", "version=1.0")])
.register()
.await?;
println!("Service registered successfully");
// 保持服务运行30秒
sleep(Duration::from_secs(30)).await;
// 注销服务
service.unregister().await?;
println!("Service unregistered");
Ok(())
}
// 服务发现示例
async fn discover_services() -> Result<(), Box<dyn std::error::Error>> {
// 创建浏览器实例
let browser = BrowseService::new("_http._tcp")
.browse()
.await?;
println!("Starting service discovery...");
// 处理发现的服务事件
while let Some(event) = browser.next().await {
match event {
ServiceEvent::ServiceFound(service) => {
println!("[Found] Service: {}", service.name());
// 解析服务详情
match service.resolve().await {
Ok(resolved) => {
println!(" Host: {}", resolved.hostname());
println!(" Port: {}", resolved.port());
println!(" IP: {:?}", resolved.ip_addresses());
// 获取TXT记录
if let Ok(txt) = resolved.get_txt_records().await {
println!(" TXT: {:?}", txt);
}
}
Err(e) => println!(" Failed to resolve: {}", e),
}
}
ServiceEvent::ServiceLost(service) => {
println!("[Lost] Service: {}", service.name());
}
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 在单独的task中运行服务注册
tokio::spawn(async {
if let Err(e) = register_service().await {
eprintln!("Service registration error: {}", e);
}
});
// 运行服务发现
discover_services().await?;
Ok(())
}
注意事项
- 在Linux系统上可能需要安装
avahi-daemon
服务 - 确保网络允许mDNS流量(UDP端口5353)
- 服务发现可能会有几秒钟的延迟
- 在生产环境中应考虑添加超时处理
性能优化建议
- 重用浏览器实例而不是频繁创建新的
- 对结果进行缓存,避免重复解析
- 合理设置查询间隔,避免过于频繁的查询
- 考虑使用
filter
方法提前过滤不需要的服务
async-dnssd
为Rust开发者提供了强大而灵活的网络服务发现能力,特别适合构建需要自动发现局域网设备的应用程序。