鸿蒙Next中使用mDNS发现局域网服务:完整指南与实战
·
什么是mDNS?
mDNS(Multicast DNS)是一种零配置网络服务发现协议,允许设备在局域网内无需传统DNS服务器即可发现服务和解析主机名。在鸿蒙生态中,mDNS是实现智能设备自动发现的理想选择。
mDNS在鸿蒙中的优势
-
零配置:设备接入网络即可自动被发现
-
局域网发现:完美适用于智能家居、IoT设备场景
-
原生支持:鸿蒙提供了完整的mDNS API支持
-
低功耗:相比轮询机制更加节能
环境配置
1. 添加权限
在module.json5文件中添加网络权限:
json
复制
下载
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_NETWORK_INFO"
}
]
}
}
2. 导入必要模块
typescript
复制
下载
import mdns from '@ohos.net.mdns';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
服务发布(服务端)
创建mDNS服务
typescript
复制
下载
class MDNSService {
private mdnsService: mdns.Service;
private context: common.BaseContext;
private isPublished: boolean = false;
constructor(context: common.BaseContext) {
this.context = context;
this.mdnsService = mdns.createMDNSService(this.context);
}
// 发布服务
async publishService(serviceName: string, serviceType: string, port: number): Promise<boolean> {
try {
const serviceInfo: mdns.ServiceInfo = {
serviceName: serviceName,
serviceType: serviceType,
port: port,
// 可选:添加TXT记录
txtRecord: {
version: '1.0',
protocol: 'tcp',
description: '鸿蒙mDNS示例服务'
}
};
await this.mdnsService.publish(serviceInfo);
this.isPublished = true;
console.info(`mDNS服务发布成功: ${serviceName}.${serviceType}`);
this.setupServiceListeners();
return true;
} catch (error) {
console.error(`发布mDNS服务失败: ${(error as BusinessError).message}`);
return false;
}
}
// 设置服务监听器
private setupServiceListeners(): void {
this.mdnsService.on('servicePublished', () => {
console.info('服务发布事件确认');
});
this.mdnsService.on('serviceUnpublished', () => {
console.info('服务取消发布');
});
this.mdnsService.on('serviceResolved', (serviceInfo: mdns.ServiceInfo) => {
console.info(`服务被解析: ${JSON.stringify(serviceInfo)}`);
});
this.mdnsService.on('serviceStopped', () => {
console.info('服务已停止');
this.isPublished = false;
});
}
// 更新服务TXT记录
async updateTxtRecord(txtRecord: Record<string, string>): Promise<boolean> {
if (!this.isPublished) {
console.error('服务未发布,无法更新TXT记录');
return false;
}
try {
await this.mdnsService.updateTxtRecord(txtRecord);
console.info('TXT记录更新成功');
return true;
} catch (error) {
console.error(`更新TXT记录失败: ${(error as BusinessError).message}`);
return false;
}
}
// 停止服务
async stopService(): Promise<void> {
if (this.isPublished) {
try {
await this.mdnsService.unpublish();
this.isPublished = false;
console.info('mDNS服务已停止');
} catch (error) {
console.error(`停止服务失败: ${(error as BusinessError).message}`);
}
}
}
// 销毁服务
destroy(): void {
this.mdnsService.off('servicePublished');
this.mdnsService.off('serviceUnpublished');
this.mdnsService.off('serviceResolved');
this.mdnsService.off('serviceStopped');
}
}
服务发布示例
typescript
复制
下载
// 发布一个智能家居服务
const mdnsService = new MDNSService(getContext(this));
// 发布服务
await mdnsService.publishService('MySmartHome', '_http._tcp', 8080);
// 更新设备状态
await mdnsService.updateTxtRecord({
version: '1.0',
status: 'online',
deviceType: 'light',
room: 'livingroom'
});
服务发现(客户端)
创建服务浏览器
typescript
复制
下载
class MDNSBrowser {
private mdnsService: mdns.Service;
private context: common.BaseContext;
private discoveredServices: Map<string, mdns.ServiceInfo> = new Map();
private discoveryCallback?: (service: mdns.ServiceInfo) => void;
private removalCallback?: (serviceName: string) => void;
constructor(context: common.BaseContext) {
this.context = context;
this.mdnsService = mdns.createMDNSService(this.context);
}
// 开始发现服务
async startDiscovery(serviceType: string): Promise<boolean> {
try {
await this.mdnsService.startDiscovering(serviceType);
console.info(`开始发现服务类型: ${serviceType}`);
this.setupDiscoveryListeners();
return true;
} catch (error) {
console.error(`启动服务发现失败: ${(error as BusinessError).message}`);
return false;
}
}
// 设置发现监听器
private setupDiscoveryListeners(): void {
this.mdnsService.on('serviceFound', (serviceInfo: mdns.ServiceInfo) => {
console.info(`发现服务: ${serviceInfo.serviceName}`);
console.info(`服务详情: ${JSON.stringify(serviceInfo)}`);
this.discoveredServices.set(serviceInfo.serviceName, serviceInfo);
if (this.discoveryCallback) {
this.discoveryCallback(serviceInfo);
}
});
this.mdnsService.on('serviceLost', (serviceInfo: mdns.ServiceInfo) => {
console.info(`服务丢失: ${serviceInfo.serviceName}`);
this.discoveredServices.delete(serviceInfo.serviceName);
if (this.removalCallback) {
this.removalCallback(serviceInfo.serviceName);
}
});
this.mdnsService.on('serviceResolved', (serviceInfo: mdns.ServiceInfo) => {
console.info(`服务解析完成: ${serviceInfo.serviceName}`);
console.info(`解析详情: ${JSON.stringify(serviceInfo)}`);
// 更新服务信息
this.discoveredServices.set(serviceInfo.serviceName, serviceInfo);
});
}
// 设置发现回调
setDiscoveryCallbacks(
discoveryCallback: (service: mdns.ServiceInfo) => void,
removalCallback?: (serviceName: string) => void
): void {
this.discoveryCallback = discoveryCallback;
this.removalCallback = removalCallback;
}
// 获取所有发现的服务
getDiscoveredServices(): mdns.ServiceInfo[] {
return Array.from(this.discoveredServices.values());
}
// 停止发现
async stopDiscovery(): Promise<void> {
try {
await this.mdnsService.stopDiscovering();
this.discoveredServices.clear();
console.info('服务发现已停止');
} catch (error) {
console.error(`停止服务发现失败: ${(error as BusinessError).message}`);
}
}
// 销毁浏览器
destroy(): void {
this.mdnsService.off('serviceFound');
this.mdnsService.off('serviceLost');
this.mdnsService.off('serviceResolved');
}
}
实战示例:智能家居设备发现
设备发布者(服务端)
typescript
复制
下载
class SmartHomeDevice {
private mdnsService: MDNSService;
private deviceInfo: DeviceInfo;
constructor(context: common.BaseContext, deviceInfo: DeviceInfo) {
this.mdnsService = new MDNSService(context);
this.deviceInfo = deviceInfo;
}
// 启动设备服务
async startDevice(): Promise<boolean> {
const serviceType = '_smarthome._tcp';
const success = await this.mdnsService.publishService(
this.deviceInfo.name,
serviceType,
this.deviceInfo.port
);
if (success) {
// 更新设备特定的TXT记录
await this.mdnsService.updateTxtRecord({
deviceId: this.deviceInfo.id,
type: this.deviceInfo.type,
version: this.deviceInfo.version,
status: 'online',
capabilities: this.deviceInfo.capabilities.join(',')
});
}
return success;
}
// 停止设备服务
async stopDevice(): Promise<void> {
await this.mdnsService.stopService();
}
}
interface DeviceInfo {
id: string;
name: string;
type: string;
port: number;
version: string;
capabilities: string[];
}
设备发现者(客户端)
typescript
复制
下载
class SmartHomeController {
private mdnsBrowser: MDNSBrowser;
private devices: Map<string, SmartHomeDeviceInfo> = new Map();
constructor(context: common.BaseContext) {
this.mdnsBrowser = new MDNSBrowser(context);
this.setupDiscoveryCallbacks();
}
// 开始发现智能家居设备
async startDiscovery(): Promise<boolean> {
return await this.mdnsBrowser.startDiscovery('_smarthome._tcp');
}
// 设置发现回调
private setupDiscoveryCallbacks(): void {
this.mdnsBrowser.setDiscoveryCallbacks(
// 设备发现回调
(service: mdns.ServiceInfo) => {
const deviceInfo = this.parseDeviceInfo(service);
this.devices.set(deviceInfo.id, deviceInfo);
console.info(`发现新设备: ${deviceInfo.name}`);
this.onDeviceDiscovered(deviceInfo);
},
// 设备丢失回调
(serviceName: string) => {
console.info(`设备离线: ${serviceName}`);
this.onDeviceLost(serviceName);
}
);
}
// 解析设备信息
private parseDeviceInfo(service: mdns.ServiceInfo): SmartHomeDeviceInfo {
return {
id: service.txtRecord?.['deviceId'] || 'unknown',
name: service.serviceName,
type: service.txtRecord?.['type'] || 'unknown',
address: service.host?.address || 'unknown',
port: service.port,
version: service.txtRecord?.['version'] || '1.0',
status: service.txtRecord?.['status'] || 'unknown',
capabilities: service.txtRecord?.['capabilities']?.split(',') || []
};
}
// 设备发现处理
private onDeviceDiscovered(device: SmartHomeDeviceInfo): void {
// 这里可以添加设备发现后的逻辑
// 比如更新UI、建立连接等
console.info(`设备详情: ${JSON.stringify(device)}`);
}
// 设备丢失处理
private onDeviceLost(serviceName: string): void {
// 处理设备离线逻辑
this.devices.delete(serviceName);
}
// 获取所有发现的设备
getDiscoveredDevices(): SmartHomeDeviceInfo[] {
return Array.from(this.devices.values());
}
// 停止发现
async stopDiscovery(): Promise<void> {
await this.mdnsBrowser.stopDiscovery();
}
}
interface SmartHomeDeviceInfo {
id: string;
name: string;
type: string;
address: string;
port: number;
version: string;
status: string;
capabilities: string[];
}
UI界面实现
typescript
复制
下载
// DeviceDiscoveryUI.ets
@Entry
@Component
struct DeviceDiscoveryPage {
private controller: SmartHomeController = new SmartHomeController(getContext(this));
@State devices: SmartHomeDeviceInfo[] = [];
@State isDiscovering: boolean = false;
aboutToAppear() {
// 设置设备更新回调
this.setupDeviceUpdate();
}
build() {
Column({ space: 20 }) {
// 标题和控制区域
Row({ space: 10 }) {
Text('智能家居设备发现')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button(this.isDiscovering ? '停止发现' : '开始发现')
.onClick(() => {
if (this.isDiscovering) {
this.stopDiscovery();
} else {
this.startDiscovery();
}
})
}
.width('100%')
.padding(10)
// 设备列表
List({ space: 10 }) {
ForEach(this.devices, (device: SmartHomeDeviceInfo) => {
ListItem() {
DeviceItem({ device: device })
}
}, (device: SmartHomeDeviceInfo) => device.id)
}
.layoutWeight(1)
.width('100%')
// 状态显示
Text(this.isDiscovering ? `发现 ${this.devices.length} 个设备` : '点击开始发现设备')
.fontSize(16)
.fontColor(Color.Gray)
}
.width('100%')
.height('100%')
.padding(20)
}
async startDiscovery() {
this.isDiscovering = await this.controller.startDiscovery();
if (this.isDiscovering) {
this.devices = this.controller.getDiscoveredDevices();
}
}
async stopDiscovery() {
await this.controller.stopDiscovery();
this.isDiscovering = false;
}
private setupDeviceUpdate() {
// 定期更新设备列表
setInterval(() => {
if (this.isDiscovering) {
this.devices = [...this.controller.getDiscoveredDevices()];
}
}, 1000);
}
}
@Component
struct DeviceItem {
@Prop device: SmartHomeDeviceInfo;
build() {
Row({ space: 15 }) {
// 设备图标
Image($r('app.media.device_icon'))
.width(40)
.height(40)
// 设备信息
Column({ space: 5 }) {
Text(this.device.name)
.fontSize(18)
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Start)
Text(`${this.device.type} | ${this.device.address}:${this.device.port}`)
.fontSize(12)
.fontColor(Color.Gray)
}
.layoutWeight(1)
// 设备状态
Text(this.device.status === 'online' ? '在线' : '离线')
.fontSize(14)
.fontColor(this.device.status === 'online' ? Color.Green : Color.Red)
}
.width('100%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(10)
.shadow({ radius: 2, color: Color.Black, offsetX: 0, offsetY: 1 })
}
}
常见服务类型
在mDNS中,服务类型遵循特定格式。以下是一些常见的服务类型:
typescript
复制
下载
const CommonServiceTypes = {
HTTP: '_http._tcp',
HTTPS: '_https._tcp',
SSH: '_ssh._tcp',
FTP: '_ftp._tcp',
PRINTER: '_printer._tcp',
AIRPLAY: '_airplay._tcp',
HOMEKIT: '_homekit._tcp',
SMART_HOME: '_smarthome._tcp',
MEDIA_SERVER: '_media-server._tcp'
} as const;
最佳实践和注意事项
1. 错误处理
typescript
复制
下载
class MDNSErrorHandler {
static handleError(error: BusinessError): void {
const errorCode = error.code;
switch (errorCode) {
case 201:
console.error('权限不足');
break;
case 202:
console.error('服务类型格式错误');
break;
case 203:
console.error('服务名称已存在');
break;
case 204:
console.error('网络不可用');
break;
default:
console.error(`mDNS错误: ${error.message}`);
}
}
}
2. 性能优化
-
合理设置发现间隔:避免频繁的服务发现
-
及时清理资源:页面销毁时停止服务发现
-
使用合适的服务类型:精确指定需要发现的服务类型
3. 安全性考虑
-
验证服务身份:通过TXT记录验证设备身份
-
加密通信:发现后建立加密连接
-
权限控制:确保只有授权设备可以发现服务
总结
mDNS在鸿蒙Next中为设备发现提供了强大的支持,特别适合智能家居、IoT设备等场景。通过本文的指南,您可以:
-
轻松发布mDNS服务供其他设备发现
-
实现自动化的设备发现和管理
-
构建零配置的智能设备网络
-
创建用户友好的设备发现界面
mDNS的零配置特性让用户体验更加流畅,用户只需将设备接入网络即可自动被发现和使用,这正符合鸿蒙分布式理念的设计哲学。
开启新对话
深度思考
联网搜索
更多推荐

所有评论(0)