Android NSD 网络服务发现

Android NSD 网络服务发现

  • Network Service Discovery 网络服务发现是一种基于 DNS-SD(mDNS)协议的本地网络服务发现机制,用于在 LAN 局域网内注册、发现和连接网络服务(比如打印机、摄像头、文件共享传输、智能家居控制和多人联机游戏等),设备无需手动配置 IP 地址或端口,无需依赖中央服务器(去中心化,通过多播 DNS 实现设备间的零配置发现和解析),设备自行发布和解析主机名称(设备上线时自动广播主机名和 IP 等消息,下线时发送注销消息),允许应用通过指定服务类型和名称来请求服务
  • DNS:域名系统(Domain Name System),用于将域名解析为 IP 地址,通常使用 UDP 单播(端口 53),也可通过 TCP 处理大报文,传统的 DNS 是一种基于 UDP 单播的集中式服务协议,依赖于特定的 DNS 中央服务器,需要配置和维护 DNS 中央服务器
  • mDNS:多播 DNS(Multicast DNS),扩展自 DNS 协议(可以理解为 DNS 在本地网络下的轻量化扩展,支持名字解析,mDNS 是 DNS 的补充),通常使用 UDP 组播(端口 5353),专为局域网设计(仅解析以 .local 结尾的域名,可以理解为局域网内的 DNS 系统),用于局域网内设备的名称解析和自动服务发现,mDNS 是一种去中心化的服务发现协议,使用 UDP 组播而不是 UDP 单播,实现设备自动注册和发现,无需依赖中央服务器
  • DNS-SD:DNS 服务发现(DNS-Based Service Discovery)是一种基于 DNS 协议扩展(扩展 DNS 记录类型:PTR、SRV 和 TXT,用于描述服务元数据,与 mDNS 兼容)的网络服务发现机制,DNS-SD 通常与 mDNS 结合使用,mDNS 负责局域网内主机名称解析(.local 域),DNS-SD 提供服务发现能力,而无需依赖传统 DNS 中央服务器(不过 DNS-SD 也支持运行在传统的 DNS 上)
  • Bonjour:是苹果公司开发的一种零配置网络协议(Zeroconf),用于局域网内设备与服务的自动发现与连接,无需手动配置 IP 地址或端口,本质整合了 mDNS 和 DNS-SD 协议,通过扩展 DNS 记录类型(比如 PTR、SRV 和 TXT)来实现网络服务注册和发现,提供跨平台 API,简化设备互联,Bonjour 看作是具体实现(也是 Zeroconf 最广泛使用的一个实现),DNS-SD 看作是协议框架(定义服务发现的逻辑标准规范),mDNS 看作是底层技术(实现局域网内的零配置解析)
  • Avahi:一个开源的 mDNS 和 DNS-SD 实现,常用于 Linux 系统中

服务注册

  • 设备可以在局域网内注册自己提供的服务
java 复制代码
private static final String SERVICE_TYPE = "_http._tcp.";
private NsdManager.RegistrationListener registrationListener;
private void registerService(Context context) {
    int port;
    ServerSocket serverSocket;
    try {
        //0 代表动态分配可用端口
        serverSocket = new ServerSocket(0);
        port = serverSocket.getLocalPort();
        serverSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    //创建服务信息
    NsdServiceInfo nsdServiceInfo = new NsdServiceInfo();
    nsdServiceInfo.setServiceName("MyNsdAndroidServer"); //服务名称
    nsdServiceInfo.setServiceType(SERVICE_TYPE); //服务类型(DNS-SD 规范)
    nsdServiceInfo.setPort(port);
    nsdServiceInfo.setAttribute("deviceType", "Android"); //自定义属性
    registrationListener = new NsdManager.RegistrationListener() {
        @Override
        public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
            Log.e(TAG, "服务注册失败,错误码:" + errorCode);
        }

        @Override
        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {

        }

        @Override
        public void onServiceRegistered(NsdServiceInfo serviceInfo) {
            String serviceName = serviceInfo.getServiceName();
            Log.d(TAG, "服务注册成功,服务名称:" + serviceName);
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo serviceInfo) {

        }
    };
    NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    //服务注册
    nsdManager.registerService(nsdServiceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
}

public void unregisterService(Context context) {
    NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    //
    if (registrationListener != null) {
        //服务反注册
        nsdManager.unregisterService(registrationListener);
    }
}

服务发现

  • 设备可以在局域网内发现其他设备提供的服务
java 复制代码
private static final String SERVICE_TYPE = "_http._tcp.";
private NsdManager.DiscoveryListener discoveryListener;
private void discoverServices(Context context) {
    NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    //
    discoveryListener = new NsdManager.DiscoveryListener() {
        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            nsdManager.stopServiceDiscovery(this);
        }
        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            nsdManager.stopServiceDiscovery(this);
        }
        @Override
        public void onDiscoveryStarted(String serviceType) {

        }
        @Override
        public void onDiscoveryStopped(String serviceType) {

        }
        @Override
        public void onServiceFound(NsdServiceInfo serviceInfo) {
            String serviceType = serviceInfo.getServiceType();
            String serviceName = serviceInfo.getServiceName();
            if (!SERVICE_TYPE.equals(serviceType)) {
                Log.e(TAG, "onServiceFound: serviceType:"+serviceType);
                return;
            }
            if ("MyNsdAndroidServer".equals(serviceName)) {
                    Log.d(TAG, "onServiceFound: Same machine(Same IP): " + serviceName);
                return;
            }
            if (serviceName.contains("MyNsdAndroidServer")){
                //后续的服务解析
                resolveService(context, serviceInfo);
            }
        }
        @Override
        public void onServiceLost(NsdServiceInfo serviceInfo) {

        }
    };
    //服务发现
    nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
}

public void stopServiceDiscovery(Context context) {
    NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    //
    if (discoveryListener != null) {
        //服务发现停止
        nsdManager.stopServiceDiscovery(discoveryListener);
    }
}

服务解析

  • 设备可以解析发现的服务,获取服务的详细信息,解析出具体的 IP 地址和端口号
java 复制代码
private void resolveService(Context context, NsdServiceInfo serviceInfo) {
    resolveListener = new NsdManager.ResolveListener() {
        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {

        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            String host = serviceInfo.getHost().getHostAddress();
            int port = serviceInfo.getPort();
            Log.d(TAG, "服务解析成功,IP 地址:" + host + ",端口:" + port);
        }
    };
    NsdManager nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    //服务解析
    nsdManager.resolveService(serviceInfo, resolveListener);
}
相关推荐
恋猫de小郭3 小时前
腾讯 Kuikly 正式开源,了解一下这个基于 Kotlin 的全平台框架
android·前端·ios
贫道绝缘子3 小时前
【Android】四大组件之Activity
android
人生游戏牛马NPC1号4 小时前
学习Android(四)
android·kotlin
_祝你今天愉快4 小时前
安卓触摸事件分发机制分析
android
fyr897574 小时前
Ubuntu 下编译goldfish内核并使用模拟器运行
android·linux
心之所向,自强不息4 小时前
关于Android Studio的Gradle各项配置
android·ide·gradle·android studio
隐-梵4 小时前
Android studio学习之路(八)---Fragment碎片化页面的使用
android·学习·android studio
百锦再4 小时前
Kotlin学习基础知识大全(上)
android·xml·学习·微信·kotlin·studio·mobile
前期后期5 小时前
Android 智能家居开发:串口是什么,为什么android版本都比较低?粘包半包的原因以及处理思路,缓冲区处理,以及超时清空缓冲区....
android·智能家居
Wgllss5 小时前
按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的
android·架构·android jetpack