android - Android,NSD/DNS-SD : NsdManager unreliable discovery and IP resolution

标签 android networking p2p discovery nsd

在过去的几周中,Android的NSD实现让我发疯了:

从用户的角度来看,会出现以下问题:

  • 设备以完全不确定的方式相互发现。如果我启动基于NsdManager的应用程序,则只要涉及两个设备,它就会或多或少地起作用。 如果加入了第三个设备,则很少会发现前两个,而前两个将看不到第三个。如果我退出这些应用程序(它们正常注销了NSD监听器)并以不同的顺序重新启动它们,则发现模式并不完全相同,而是相似的。
  • 在我的家庭网络中,发现的设备的IP分辨率基本上可以按预期工作。在工作中,有时即使仅使用两个设备(A和B),设备A也会使用A的IP地址和B的端口解析设备B的服务,反之亦然。因此,IP地址和服务名称似乎以某种方式在较低级别(可能是NsdManager)混合在一起。

  • 现在,我已经针对此(https://code.google.com/p/android/issues/detail?id=201314&thanks=201314&ts=1455814995)在Google代码上提交了错误报告。我也将其发布在这里,希望能获得更多反馈。也许我的Nsd帮助器类中出现错误。

    首先,经过无休止的调试,现在我在日志猫中发现了一些提示,即Android的基础NsdService本身可能正在发生故障,而MDnsDS似乎可以正常工作。但是我不确定...

    这是一些说明问题的日志输出(已过滤某些消息以提高可读性):
    02-18 16:57:02.327: D/NsdService(628): startMDnsDaemon
    02-18 16:57:02.327: D/MDnsDS(187): Starting MDNSD
    02-18 16:57:02.529: D/NsdService(628): New client listening to asynchronous messages
    02-18 16:57:02.529: D/NsdService(628): New client, channel: com.android.internal.util.AsyncChannel@1fa188ce messenger: android.os.Messenger@cca33ef
    02-18 16:57:02.532: D/NsdService(628): Register service
    02-18 16:57:02.532: D/NsdService(628): registerService: 106 name: TuSync-0.57392, type: _tusync._tcp., host: /::, port: 57392
    02-18 16:57:02.533: D/MDnsDS(187): serviceRegister(106, (null), TuSync-0.57392, _tusync._tcp., (null), (null), 57392, 0, <binary>)
    02-18 16:57:02.533: D/MDnsDS(187): serviceRegister successful
    02-18 16:57:02.534: D/NsdService(628): Register 1 106
    02-18 16:57:04.083: D/MDnsDS(187): register succeeded for 106 as TuSync-0.57392
    02-18 16:57:04.087: D/NsdService(628): SERVICE_REGISTERED Raw: 606 106 "TuSync-0.57392"
    02-18 16:57:04.109: D/NsdService(628): Discover services
    02-18 16:57:04.109: D/NsdService(628): discoverServices: 107 _tusync._tcp.
    02-18 16:57:04.110: D/MDnsDS(187): discover((null), _tusync._tcp., (null), 107, 0)
    02-18 16:57:04.110: D/MDnsDS(187): discover successful
    02-18 16:57:04.110: D/NsdService(628): Discover 2 107_tusync._tcp.
    02-18 16:57:04.333: D/MDnsDS(187): Discover found new serviceName TuSync-0.57392, regType _tusync._tcp. and domain local. for 107
    02-18 16:57:04.334: D/NsdService(628): SERVICE_FOUND Raw: 603 107 "TuSync-0.57392" _tusync._tcp. local.
    02-18 16:57:04.338: D/NsdService(628): Resolve service
    02-18 16:57:04.338: D/NsdService(628): resolveService: 108 name: TuSync-0.57392, type: _tusync._tcp., host: null, port: 0
    02-18 16:57:04.339: D/MDnsDS(187): resolveService(108, (null), TuSync-0.57392, _tusync._tcp., local.)
    02-18 16:57:04.345: D/MDnsDS(187): startMonitoring 108
    02-18 16:57:04.345: D/MDnsDS(187): resolveService successful
    02-18 16:57:04.346: D/MDnsDS(187): resolve succeeded for 108 finding TuSync-0\.57392._tusync._tcp.local. at Android-3.local.:57392 with txtLen 1
    02-18 16:57:04.347: D/NsdService(628): SERVICE_RESOLVED Raw: 608 108 "TuSync-0\\.57392._tusync._tcp.local." "Android-3.local." 57392 1
    02-18 16:57:04.347: D/NsdService(628): stopResolveService: 108
    02-18 16:57:04.347: D/MDnsDS(187): Stopping resolve with ref 0xb5c4734c
    02-18 16:57:04.349: D/NsdService(628): getAdddrInfo: 109
    02-18 16:57:04.349: D/MDnsDS(187): getAddrInfo(109, (null) 0, Android-3.local.)
    02-18 16:57:04.350: D/MDnsDS(187): getAddrInfo successful
    02-18 16:57:04.352: D/MDnsDS(187): getAddrInfo succeeded for 109: 109 "Android-3.local." 120 10.0.0.4
    02-18 16:57:04.352: D/MDnsDS(187): getAddrInfo succeeded for 109: 109 "Android-3.local." 120 fe80::204:4bff:fe2c:6c87
    02-18 16:57:04.354: D/NsdService(628): SERVICE_GET_ADDR_SUCCESS Raw: 612 109 "Android-3.local." 120 10.0.0.4
    02-18 16:57:04.354: D/NsdService(628): stopGetAdddrInfo: 109
    02-18 16:57:04.355: D/MDnsDS(187): Stopping getaddrinfo with ref 0xb5c472d4
    02-18 16:57:04.364: E/NsdService(628): Unique id with no client mapping: 109
    02-18 16:57:04.364: E/NsdService(628): Unhandled { when=-10ms what=393242 obj=com.android.server.NsdService$NativeEvent@86af300 target=com.android.internal.util.StateMachine$SmHandler }
    02-18 16:57:04.627: D/MDnsDS(187): Discover found new serviceName TuSync-0.36230, regType _tusync._tcp. and domain local. for 107
    02-18 16:57:04.632: D/MDnsDS(187): Discover found new serviceName TuSync-0.60493, regType _tusync._tcp. and domain local. for 107
    02-18 16:57:04.633: D/NsdService(628): SERVICE_FOUND Raw: 603 107 "TuSync-0.36230" _tusync._tcp. local.
    02-18 16:57:04.634: D/NsdService(628): SERVICE_FOUND Raw: 603 107 "TuSync-0.60493" _tusync._tcp. local.
    02-18 16:57:04.635: D/NsdService(628): Resolve service
    02-18 16:57:04.635: D/NsdService(628): resolveService: 110 name: TuSync-0.36230, type: _tusync._tcp., host: null, port: 0
    02-18 16:57:04.636: D/MDnsDS(187): resolveService(110, (null), TuSync-0.36230, _tusync._tcp., local.)
    02-18 16:57:04.637: D/MDnsDS(187): resolve succeeded for 110 finding TuSync-0\.36230._tusync._tcp.local. at Android.local.:36230 with txtLen 1
    02-18 16:57:04.638: D/NsdService(628): Resolve service
    02-18 16:57:04.638: D/NsdService(628): SERVICE_RESOLVED Raw: 608 110 "TuSync-0\\.36230._tusync._tcp.local." "Android.local." 36230 1
    02-18 16:57:04.639: D/NsdService(628): stopResolveService: 110
    02-18 16:57:04.639: D/MDnsDS(187): Stopping resolve with ref 0xb5c473c4
    02-18 16:57:04.643: D/MDnsDS(187): getAddrInfo succeeded for 111: 111 "Android.local." 120 10.0.0.5
    02-18 16:57:04.643: D/MDnsDS(187): getAddrInfo succeeded for 111: 111 "Android.local." 120 fe80::204:4bff:fe26:8483
    02-18 16:57:04.644: D/NsdService(628): SERVICE_GET_ADDR_SUCCESS Raw: 612 111 "Android.local." 120 10.0.0.5
    02-18 16:57:04.644: D/NsdService(628): stopGetAdddrInfo: 111
    02-18 16:57:04.645: D/MDnsDS(187): Stopping getaddrinfo with ref 0xb5c47364
    02-18 16:57:04.645: D/MDnsDS(187): Going to poll with pollCount 3
    02-18 16:57:04.658: E/NsdService(628): Unique id with no client mapping: 111
    02-18 16:57:04.658: E/NsdService(628): Unhandled { when=-14ms what=393242 obj=com.android.server.NsdService$NativeEvent@1d93a739 target=com.android.internal.util.StateMachine$SmHandler }
    

    有关上下文的一些说明:
  • 我的NSD服务类型是_tusync._tcp。
  • 我以TuSync-0。[本地端口号]的格式为所有节点创建唯一的服务名称,以防止命名冲突并简化调试。
  • 在此测试方案中,有三个设备。记录设备的IP为10.0.0.4,端口为57392。

  • 日志显示,底层MDnsDS守护程序正确发现并解析了所有节点。但是,上面的NsdService不会传播所有分辨率。在16:57:04.627似乎存在ID冲突,在该设备的两个对等方(TuSync-0.36230和TuSync-0.60493)都被分配了内部ID 107(如果我仅通过查看日志正确地解释了机制) 。发现两个节点后,我会通知我在discoveryListener中注册的NsdManager,但是,解析仅适用于其中一个,另一个会触发错误:
    02-18 16:57:04.638: E/NsdHelper(6370): Resolve failed with error code:
    3. Service: name: TuSync-0.60493, type: _tusync._tcp., host: null, port: 0
    

    我还遇到了其他情况,即NsdService在日志中发出“SERVICE_FOUND Raw”消息后,未通知我的发现监听器。示例日志(经过大量过滤;与上述测试设置相同):
    02-18 17:54:06.692: D/MDnsDS(187): Starting MDNSD
    02-18 17:54:06.896: D/NsdService(628): registerService: 112 name: TuSync-0.57392, type: _tusync._tcp., host: /::, port: 57392
    02-18 17:54:06.896: D/MDnsDS(187): serviceRegister(112, (null), TuSync-0.57392, _tusync._tcp., (null), (null), 57392, 0, <binary>)
    02-18 17:54:06.896: D/MDnsDS(187): serviceRegister successful
    02-18 17:54:08.802: D/NsdService(628): SERVICE_REGISTERED Raw: 606 112 "TuSync-0.57392"
    02-18 17:54:08.820: D/NsdService(628): Discover services
    02-18 17:54:09.050: D/MDnsDS(187): Discover found new serviceName TuSync-0.57392, regType _tusync._tcp. and domain local. for 113
    02-18 17:54:09.050: D/NsdService(628): SERVICE_FOUND Raw: 603 113 "TuSync-0.57392" _tusync._tcp. local.
    02-18 17:54:09.211: D/MDnsDS(187): Discover found new serviceName TuSync-0.60493, regType _tusync._tcp. and domain local. for 113
    02-18 17:54:09.212: D/NsdService(628): SERVICE_FOUND Raw: 603 113 "TuSync-0.60493" _tusync._tcp. local.
    02-18 17:54:09.215: D/NsdService(628): resolveService: 116 name: TuSync-0.60493, type: _tusync._tcp., host: null, port: 0
    02-18 17:54:09.216: D/MDnsDS(187): resolveService(116, (null), TuSync-0.60493, _tusync._tcp., local.)
    02-18 17:54:09.217: D/MDnsDS(187): resolve succeeded for 116 finding TuSync-0\.60493._tusync._tcp.local. at Android-2.local.:60493 with txtLen 1
    02-18 17:54:09.219: D/NsdService(628): SERVICE_RESOLVED Raw: 608 116 "TuSync-0\\.60493._tusync._tcp.local." "Android-2.local." 60493 1
    02-18 17:54:09.228: D/MDnsDS(187): getAddrInfo succeeded for 117: 117 "Android-2.local." 120 10.0.0.6
    02-18 17:54:09.228: D/MDnsDS(187): getAddrInfo succeeded for 117: 117 "Android-2.local." 120 fe80::c643:8fff:fec5:5648
    02-18 17:54:09.229: D/NsdService(628): SERVICE_GET_ADDR_SUCCESS Raw: 612 117 "Android-2.local." 120 10.0.0.6
    02-18 17:54:09.244: D/MDnsDS(187): Discover found new serviceName TuSync-0.36230, regType _tusync._tcp. and domain local. for 113
    02-18 17:54:09.251: E/NsdService(628): Unique id with no client mapping: 117
    02-18 17:54:09.251: E/NsdService(628): Unhandled { when=-22ms what=393242 obj=com.android.server.NsdService$NativeEvent@1e992653 target=com.android.internal.util.StateMachine$SmHandler }
    02-18 17:54:09.255: D/NsdService(628): SERVICE_FOUND Raw: 603 113 "TuSync-0.36230" _tusync._tcp. local.
    

    在这种情况下,发现的对等体10.0.0.5(端口36230)不会触发DiscoveryDiscovery通知。在最后一条日志消息之后,什么都没有发生。因此,我的日志记录节点10.0.0.4仅发现了另一个对等节点10.0.0.6:60493。

    类似错误报告的数量很少,让我想知道我是否是仅有的出现这些问题的人,或者NsdManager是否完全不稳定并且没有人使用它?

    作为引用,这是我的帮助程序类的代码-与Android NSD聊天教程相似,但是由于该教程似乎会引起一些其他错误,因此我尝试对其进行改进。
    public final class NsdHelper {
    
        public static final String TAG = "NsdHelper";
    
        private final Context mContext;
    
        private final NsdManager mNsdManager;
    
        private final String mBaseServiceName; // Base component of the service name, e.g. "service_xy"
        private String mServiceName; // Service name of the local node, may be updated upon peer detection with service name conflicts, e.g. to "service_xy (2)"
        private final String mServiceType;
    
        private final NsdHandler mNsdHandler;
    
        private MyRegistrationListener mRegistrationListener;
        private final Object mRegistrationLock = new Object();
    
        private MyDiscoveryListener mDiscoveryListener;
        private final Object mDiscoveryLock = new Object();
    
        private final Object mResolveLock = new Object();
        private final Semaphore mResolveSemaphore;
    
        public NsdHelper(Context context, String baseServiceName, String serviceName, String serviceType, NsdHandler nsdHandler) {
            mContext = context;
            mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
            mNsdHandler = nsdHandler;
            mBaseServiceName = baseServiceName;
            mServiceName = serviceName;
            mServiceType = serviceType;
    
            mResolveSemaphore = new Semaphore(10, true);
        }
    
        /*********************
         * Lifecycle methods *
         *********************/
    
        public void registerLocalService(final int port) {
    
            NsdServiceInfo localServiceInfo = new NsdServiceInfo();
            localServiceInfo.setServiceName(mServiceName);
            localServiceInfo.setServiceType(mServiceType);
            localServiceInfo.setPort(port);
    
            synchronized (mRegistrationLock) {
                if (mRegistrationListener == null) {
                    mRegistrationListener = new MyRegistrationListener();
                    // try {
                    mNsdManager.registerService(
                            localServiceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
    
                    /*} catch (Exception e) {
                        MLog.e(TAG, "Exception registering service; trying to unregister.", e);
                        unregisterLocalService();
    
                        mNsdHandler.onRegistrationFailed(localServiceInfo, 0);
                    }*/
                } else {
                    MLog.w(TAG, "registerLocalService called while service registration already in progress or service already registered.");
                }
            }
        }
    
        public void unregisterLocalService() {
            synchronized (mRegistrationLock) {
                if (mRegistrationListener != null) {
                    // try {
                        mNsdManager.unregisterService(mRegistrationListener);
                    /*} catch (IllegalArgumentException e) {
                        MLog.w(TAG, "Exception trying to unregister registrationListener.");
                    }*/
                    mRegistrationListener = null;
                } else {
                    MLog.w(TAG, "unregisterLocalService called while service not yet registered or already unregistered.");
                }
            }
        }
    
        public void startDiscovery() {
            synchronized(mDiscoveryLock) {
                if(mDiscoveryListener == null) {
                    mDiscoveryListener = new MyDiscoveryListener();
                    mNsdManager.discoverServices(
                            mServiceType, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
                } else {
                    MLog.w(TAG, "StartDiscovery called while discovery is already in progress.");
                }
            }
        }
    
        public void stopDiscovery() {
            synchronized (mDiscoveryLock) {
                if (mDiscoveryListener != null) {
                    mNsdManager.stopServiceDiscovery(mDiscoveryListener);
                    mDiscoveryListener = null;
                } else {
                    MLog.w(TAG, "StopDiscovery called while no discovery is in progress.");
                }
            }
        }
    
        public void tearDown() {
            MLog.v(TAG, "NsdHelper: tearDown()");
            stopDiscovery();
            unregisterLocalService(); // TODO this causes an exception, when the listener is already unregistered
        }
    
        /**
         * Returns the current service name of the service.
         * @return
         */
        public String getServiceName() {
            return mServiceName;
        }
    
        /**
         * Convenience method to initiate service resolution
         * @param serviceInfo NsdServiceInfo object for the service to be resolved
         */
        private void resolveService(NsdServiceInfo serviceInfo) {
            try {
                MLog.vv(TAG, "Resolving service: acquiring semaphore.");
                mResolveSemaphore.acquire();
                MLog.vv(TAG, "Resolving service: semaphore acquired.");
            } catch (InterruptedException e) {
                MLog.w(TAG, "resolveService: Waiting for acquisition of semaphore interrupted.");
            }
            mNsdManager.resolveService(serviceInfo, new MyResolveListener(serviceInfo.getServiceName()));
        }
    
        /*************
         * Listeners *
         *************/
    
        private class MyDiscoveryListener implements NsdManager.DiscoveryListener {
    
            @Override
            public void onDiscoveryStarted(String regType) {
                MLog.d(TAG, "Service discovery started");
                mNsdHandler.onDiscoveryStarted();
            }
    
            @Override
            public void onServiceFound(NsdServiceInfo serviceInfo) {
                MLog.d(TAG, "Discovered service: " + serviceInfo);
    
                // Protocol matches?
                if (!serviceInfo.getServiceType().equals(mServiceType)) {
                    MLog.v(TAG, "Discovered: other serviceType: " + serviceInfo.getServiceType());
                }
                // Make sure, that service name matches, and just resolve remote host
                else if (serviceInfo.getServiceName().contains(mBaseServiceName)){
                    MLog.d(TAG, "Discovered: correct serviceType: " + mBaseServiceName);
                    resolveService(serviceInfo);
                }
                else {
                    // Other service name, log anyway
                    MLog.d(TAG, "Discovered: service with different serviceName: " + serviceInfo.getServiceName() + ". Ignoring.");
                }
            }
    
            @Override
            public void onServiceLost(NsdServiceInfo service) {
                MLog.e(TAG, "Service lost: " + service);
                mNsdHandler.onRemotePeerLost(service);
            }
    
            @Override
            public void onDiscoveryStopped(String serviceType) {
                MLog.v(TAG, "Discovery stopped: " + serviceType);
                mNsdHandler.onDiscoveryStopped();
            }
    
            @Override
            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                MLog.e(TAG, "Discovery starting failed. Error code: " + errorCode);
                synchronized (mDiscoveryLock) {
                    mDiscoveryListener = null;  // just throw away the discovery listener, explicit stopping of the discovery should not be needed according to
                                                // https://code.google.com/p/android/issues/detail?id=99510&q=nsd&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
                }
            }
    
            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                MLog.e(TAG, "Discovery stopping failed. Error code: " + errorCode);
                // try again
                // mNsdManager.stopServiceDiscovery(this); // This should not be needed according to https://code.google.com/p/android/issues/detail?id=99510&q=nsd&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
            }
        };
    
        private class MyRegistrationListener implements NsdManager.RegistrationListener {
    
            @Override
            public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
                MLog.d(TAG, "Service registered. NsdServiceInfo: " + nsdServiceInfo);
    
                boolean nameChanged = false;
    
                // Update service name of this node (might change due to automatic conflict resolution!)
                if(!mServiceName.equals(nsdServiceInfo.getServiceName())){
                    mServiceName = nsdServiceInfo.getServiceName();
    
                    nameChanged = true;
                    MLog.d(TAG, "Local service name updated to: " + mServiceName);
                }
    
                // Notify
                if (mNsdHandler != null) {
                    mNsdHandler.onRegistrationSuccess(nsdServiceInfo);
    
                    if (nameChanged) {
                    mNsdHandler.onLocalServiceNameChanged(mServiceName);
                    }
                } else {
                    MLog.w(TAG, "onServiceRegistered: NsdHandler is null.");
                }
            }
    
            @Override
            public void onRegistrationFailed(NsdServiceInfo arg0, int arg1) {
                MLog.w(TAG, "Service registration failed with error code " + arg1 + ".");
    
                if (mNsdHandler == null) {
                    MLog.w(TAG, "onRegistrationFailed: NsdHandler is null.");
                    return;
                }
    
                mNsdHandler.onRegistrationFailed(arg0, arg1);
            }
    
            @Override
            public void onServiceUnregistered(NsdServiceInfo arg0) {
                MLog.d(TAG, "Service unregistered.");
    
                if (mNsdHandler == null) {
                    MLog.w(TAG, "onServiceUnRegistered: NsdHandler is null.");
                    return;
                }
            }
    
            @Override
            public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
                MLog.w(TAG, "Service unregistering failed.");
    
                if (mNsdHandler == null) {
                    MLog.w(TAG, "onUnRegistrationFailed: NsdHandler is null.");
                    return;
                }
            }
    
        };
    
        private class MyResolveListener implements NsdManager.ResolveListener {
    
            private final String mServiceName;
    
            public MyResolveListener(String serviceName) {
                mServiceName = serviceName;
            }
    
            @Override
            public void onResolveFailed(final NsdServiceInfo serviceInfo, int errorCode) {
                // Release resource
                mResolveSemaphore.release();
    
                MLog.e(TAG, "Resolve failed with error code: " + errorCode + ". Service: " + serviceInfo);
                if((serviceInfo.getServiceName() != null) && (!serviceInfo.getServiceName().equals(mServiceName))) {
                    MLog.e(TAG, "Service name changed: " + mServiceName + " => " + serviceInfo.getServiceName());
                }
            }
    
            @Override
            public void onServiceResolved(final NsdServiceInfo serviceInfo) {
                // Release resource
                mResolveSemaphore.release();
    
                MLog.v(TAG, "Resolve succeeded. Service: " + serviceInfo + ", Address: " + serviceInfo.getHost().getHostAddress() + ":" + serviceInfo.getPort());
                if((serviceInfo.getServiceName() != null) && (!serviceInfo.getServiceName().equals(mServiceName))) {
                    MLog.w(TAG, "Service name changed: " + mServiceName + " => " + serviceInfo.getServiceName());
                }
    
                mNsdHandler.onNewRemotePeerResolved(serviceInfo);
            }
        };
    
    
    
        /**
         * Interface for handlers that deal just with essential NSD events.
         * @author Alexander Fischl (alexander.fischl@semeion.net)
         */
        public interface NsdHandler {
    
            /**
             * Called, when the NSD manager registered the service successfully.
             * @param nsdServiceInfo
             */
            public void onRegistrationSuccess(final NsdServiceInfo nsdServiceInfo);
    
            /**
             * Called, when the NSD registration was unsuccessful.
             */
            public void onRegistrationFailed(final NsdServiceInfo nsdServiceInfo, final int errorCode);
    
    
            /**
             * Called, when the NSD manager discovers a new peer. Services registered on the
             * local machine DO NOT trigger this call!
             * @param nsdServiceInfo
             */
            public void onNewRemotePeerDiscovered(final NsdServiceInfo nsdServiceInfo);
    
            /**
             * Called, when the NSD manager resolves a new peer, yielding the connection data.
             * Services registered on the local machine DO NOT trigger this call!
             * @param nsdServiceInfo
             */
            public void onNewRemotePeerResolved(final NsdServiceInfo nsdServiceInfo);
    
            /**
             * Called, when the NSD manager loses an already discovered peer.
             * @param nsdServiceInfo
             */
            public void onRemotePeerLost(final NsdServiceInfo nsdServiceInfo);
    
            /**
             * Called, when the local service name needs to be updated (e.g. due to
             * conflict resolution when the local service is registered, and the chosen service
             * name is already taken by another node in the network.)
             * @param newLocalServiceName
             */
            public void onLocalServiceNameChanged(String newLocalServiceName);
    
            /**
             * Called, when the service discovery has successfully started.
             */
            public void onDiscoveryStarted();
    
            /**
             * Called, when the service discovery was halted.
             */
            public void onDiscoveryStopped();
        }
    }
    

    请注意,我什至实现了一个可以设置为1的信号量,以防止并行解析多个服务,因为其他人报告了并行解析的问题。但是,将其设置为1无效,因为有时正在进行的解析既不会成功也不会失败。这将导致信号量不被释放,并且NsdManager线程将永久卡在下一个解析请求中。

    还有其他人遇到这样的问题吗? 如果能够成功使用NsdManager的人也发表评论,我会很高兴-这至少意味着我遇到了可以解决的问题:)

    我已经考虑放弃NSD并实现自己的广播/多播发现机制。从理论上讲这可能很容易,但是我已经读到Android上的多播也是PITA,因为某些设备阻止了它。

    最佳答案

    与Android NSD仍然没有区别。我一直在使用棉花糖版本的Android,而NSD实际上仍然不可靠。我用RxDNSSD(https://github.com/andriydruk/RxDNSSD)替换了NSD。到目前为止,很少有类轮代码可以完美运行。

    我测试了NSD和RXDNSSD,当RXDNSSD一直工作时,NSD能够发现服务,但无法解析IP地址。

    希望对其他用户有帮助。

    关于android - Android,NSD/DNS-SD : NsdManager unreliable discovery and IP resolution,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35488850/

    相关文章:

    android - 使用水平 ScrollView 的选项卡主机自动滚动 - 以编程方式

    android - 如何在App上显示一次启动画面?

    Android Eclipse 仅按需生成 R 文件

    linux - 为什么 linux 路由配置在两个 NIC 冗余(主/辅)时失败?

    java - 使用第三方建立连接绕过防火墙

    android - Android Studio 0.8-不再运行自定义任务

    java - 如何在 Java 中高效地创建 Web 数据结构?

    android - 我可以获取通过 wifi 连接的接入点的 IP 地址吗?

    algorithm - 如何估计P2P网络中的节点总数?

    git - 我可以为 git 创建自定义协议(protocol)吗?