Android, NSD / DNS-SD: ненадежное обнаружение NsdManager и разрешение IP

В последние недели реализация NSD для Android сводит меня с ума:

С точки зрения пользователя возникают следующие проблемы:

  • Устройства обнаруживают друг друга совершенно недетерминированным образом. Если я запускаю свое приложение на основе NsdManager, оно работает более или менее, если задействованы только два устройства. Если подключается третье устройство, оно редко обнаруживает первые два, а первые два не видят третье. Если я выхожу из приложений (они аккуратно отменяют регистрацию слушателей NSD) и перезапускаю их в другом порядке, шаблон обнаружения будет не таким же, но похожим.

  • В моей домашней сети разрешение IP обнаруженных устройств в основном работает должным образом. На работе, иногда даже при использовании только двух устройств (A и B), устройство A разрешает службу устройства B с помощью IP-адреса A и порта B и наоборот. Таким образом, каким-то образом кажется, что IP-адрес и имя службы смешиваются на более низком уровне (вероятно, NsdManager).

Теперь я отправил отчет об ошибке в коде Google для этого (https://code.google.com/p/android/issues/detail?id=201314&thanks=201314&ts=1455814995). Я тоже публикую это здесь в надежде получить больше отзывов; возможно, у меня что-то не так в моем вспомогательном классе Nsd.

Прежде всего, после бесконечной отладки я обнаружил в logcat подсказки, что базовый NsdService Android сам может работать неправильно, в то время как 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, где обоим одноранговым узлам устройства (TuSync-0.36230 и TuSync-0.60493) назначается внутренний идентификатор 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) не запускает уведомление DiscoveryListener. После последнего сообщения журнала ничего не происходит. Итак, мой узел регистрации 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 ([email protected])
     */
    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, потому что некоторые устройства препятствуют этому ...


person Newtron    schedule 18.02.2016    source источник
comment
Я тоже считаю НРД нестабильным. Я провел несколько тестов, и он всегда разрешает один и тот же IP-адрес независимо от регистрации устройства. И даже более того, у меня 2 устройства, но он регистрирует в сети 6-7 сервисов.   -  person Matei Suica    schedule 24.07.2016
comment
То же самое и здесь, после нескольких дней разрешения и открытия ничего не показывают. Мне нужно перезагрузить устройства, чтобы nsd снова заработал   -  person Superbiji    schedule 07.05.2017
comment
Поскольку вы попросили комментарий, я собираюсь запустить NsdManager (или, по крайней мере, попробовать альтернативу ниже). Это работает, но по какой-то причине поиск моей рекламируемой службы (Windows, использующей Arkane Zeroconf) занимает больше минуты, чтобы найти ее.   -  person JoeHz    schedule 10.03.2019


Ответы (2)


По-прежнему никакой разницы с Android NSD. Я использовал версию Android Marshmallow, и на самом деле NSD все еще ненадежен. Я заменил NSD на RxDNSSD (https://github.com/andriydruk/RxDNSSD). Некоторые лайнеры работают до сих пор безупречно.

Я тестировал NSD и RXDNSSD, NSD смог обнаружить службу, но не смог определить IP-адрес, в то время как RXDNSSD работал все время.

Надеюсь, это поможет другим пользователям.

person NEERAJ SWARNKAR    schedule 05.07.2017

Вероятно, это больше не актуально, но я обнаружил одну из возможных причин моей проблемы: по моему опыту кажется, что NSD ведет себя крайне ненадежно, если вы выполняете дальнейшую обработку в потоке методов обратного вызова NsdManager. Даже если есть всего несколько строк кода, происходят самые странные результаты в отношении обнаружения. Таким образом, необходимо переложить любую работу из методов обратного вызова в другой поток и избегать блокировки NsdManager любой ценой, даже на миллисекунду.

person Newtron    schedule 15.06.2020
comment
Вы используете обработчик вместо этого для работы с основным потоком? Применимо ли это только к DiscoveryListener обратным вызовам или ResolveListener также к обратным вызовам? - person tmm1; 18.03.2021
comment
@ tmm1 Я больше не занимался этим, но я бы создал другой поток, чтобы разгрузить работу, который не блокирует обратные вызовы NSD. - person Newtron; 20.03.2021