Не удается обнаружить службу с помощью Network Service Discovery (NSD) на Android

Я новичок, пытающийся использовать NSD в приложении, которое я создаю, чтобы найти одноранговые узлы, работающие с той же службой в той же сети Wi-Fi, и подключиться к ней.

[См. код] На одном устройстве работает HostActivity.java, а на другом — GuestActivity.java. Нажатие плавающей кнопки на хосте регистрирует службу на порту 9000 (предустановлено на данный момент), а нажатие на нее в гостевой системе запускает обнаружение службы для того же. Оба подключены к одной и той же сети Wi-Fi.

В своем логарифме я наблюдаю, что регистрация из HostActivity.java работает нормально — я получаю необходимые сообщения журнала из NsdHelper.java. Однако запуск GuestActivity.java просто регистрирует "Обнаружение службы запущено" и никогда не приводит к разрешению службы, существующей в сети.

Что я делаю не так? Пожалуйста помоги.

Соответствующий код -

HostActivity.java

NsdHelper mNsdHelper;

public static final String TAG = "ABC";
private final int ABC_PORT = 9000;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shared_list);


    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);


    mNsdHelper = new NsdHelper(this);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Started Registration", Snackbar.LENGTH_LONG)
                    .setAction("CLOSE", null).show();
            mNsdHelper.initializeNsd();
            mNsdHelper.registerService(ABC_PORT);
            Snackbar.make(view, "Completed Registration", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();

        }
    });
}

@Override
protected void onPause() {
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    if (mNsdHelper != null) {
        mNsdHelper.initializeNsd();
        mNsdHelper.registerService(ABC_PORT);
    }
}

@Override
protected void onDestroy() {
    mNsdHelper.tearDown();
    super.onDestroy();
}

GuestActivity.java

NsdHelper mNsdHelper;

public static final String TAG = "ABC";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shared_list);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    mNsdHelper = new NsdHelper(this);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Searching for available services", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
            mNsdHelper.initializeNsd();
            mNsdHelper.discoverServices();
        }
    });
}

@Override
protected void onPause() {
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    if(mNsdHelper != null) {
        mNsdHelper.initializeNsd();
        mNsdHelper.discoverServices();
    }
}

@Override
protected void onDestroy() {
    mNsdHelper.tearDown();
    super.onDestroy();
}

NsdHelper.java — содержит все сведения о реализации NSD.

public class NsdHelper {
    Context mContext;

    NsdManager mNsdManager;
    NsdManager.ResolveListener mResolveListener;
    NsdManager.DiscoveryListener mDiscoveryListener;
    NsdManager.RegistrationListener mRegistrationListener;

    private static final String SERVICE_TYPE = "_http._tcp.";

    private static final String TAG = "NsdHelper";
    private String mServiceName = "ABC";

    // First step : register a NsdServiceInfo object to advertise your service
    NsdServiceInfo mService;

    public NsdHelper(Context context) {
    mContext = context;
    mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
}


public void initializeNsd() {
    initializeRegistrationListener();
    initializeDiscoveryListener();
    initializeResolveListener();

}


// Check success of service registration
public void initializeRegistrationListener() {
    mRegistrationListener = new NsdManager.RegistrationListener() {

        @Override
        public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
            mServiceName = nsdServiceInfo.getServiceName();
            Log.d(TAG, "Registered name : " + mServiceName);
        }

        @Override
        public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int arg1) {
            Log.d(TAG, "Registration Failed");
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
            Log.d(TAG, "Unregistered");
        }

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

    };
}

public void registerService(int port) {
    NsdServiceInfo serviceInfo  = new NsdServiceInfo();
    serviceInfo.setPort(port);
    serviceInfo.setServiceName(mServiceName);
    serviceInfo.setServiceType(SERVICE_TYPE);

    mNsdManager.registerService(
            serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);

}

// To discover services of the type you're looking for on the network
public void initializeDiscoveryListener() {
    mDiscoveryListener = new NsdManager.DiscoveryListener() {

        @Override
        public void onDiscoveryStarted(String regType) {
            Log.d(TAG, "Service discovery started");
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            Log.d(TAG, "Service discovery success : " + service);
            Log.d(TAG, "Host = "+ service.getServiceName());
            Log.d(TAG, "port = " + String.valueOf(service.getPort()));

            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
            } else if (service.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same machine: " + mServiceName);
            } else if (service.getServiceName().contains(mServiceName)){
                mNsdManager.resolveService(service, mResolveListener);
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            Log.e(TAG, "service lost" + service);
            if (mService == service) {
                mService = null;
                Log.e(TAG, "service lost" + service);
            }
        }

        @Override
        public void onDiscoveryStopped(String serviceType) {
            Log.i(TAG, "Discovery stopped: " + serviceType);
        }

        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }

        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }
    };
}

public void discoverServices() {
    mNsdManager.discoverServices(
            SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}


// Connection handshake
public void initializeResolveListener() {
    mResolveListener = new NsdManager.ResolveListener() {

        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            Log.e(TAG, "Resolve failed" + errorCode);
        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            Log.e(TAG, "Resolve Succeeded. " + serviceInfo);

            if (serviceInfo.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same IP.");
                return;
            }
            mService = serviceInfo;
            int port = mService.getPort();
            InetAddress host = mService.getHost();
        }
    };
}

public void stopDiscovery() {
    if (mNsdManager != null) {
        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    }
}

public NsdServiceInfo getChosenServiceInfo() {
    return mService;
}

public void tearDown() {
    if (mNsdManager != null) {
        if (mRegistrationListener != null) {
            mNsdManager.unregisterService(mRegistrationListener);
        }
        if (mDiscoveryListener != null) {
            mNsdManager.stopServiceDiscovery(mDiscoveryListener);
        }
    }
}

}


person fwx    schedule 15.04.2016    source источник
comment
Я никогда не играл с NSD, поэтому никаких рекомендаций относительно этого кода у меня нет. В таких случаях я пытаюсь найти какой-нибудь существующий работающий код, а затем медленно модифицирую этот код, пока он не сделает то, что мне нужно. Либо я со временем пойму, где я что-то ломаю, либо получу работающий код. :-) У Google может быть образец NSD, и я, кажется, припоминаю, что видел, как на недавней конференции Android (droidcon.it 2016?) была презентация по NSD, которая могла включать рабочий образец.   -  person CommonsWare    schedule 17.04.2016
comment
Большая часть (все?) основного кода NSD в основном взята дословно от разработчика. .android.com/training/connect-devices-wireless/ - так что я не могу приступить к изменениям в нем, если база от самого Google не работает. Я также просмотрел аналогичный код, который утверждает, что работает (хотя и 2 года назад) здесь — jayrambhia.com/blog/android-wireless-connection-1 Но это тоже не работает. Я поищу презентации droidcon о том же - будем надеяться, что я могу найти что-нибудь. Спасибо за чаевые.   -  person fwx    schedule 17.04.2016
comment
Если бы вызывался public void onServiceFound (служба NsdServiceInfo), вы бы, по крайней мере, увидели свои операторы журнала. Я запускаю аналогичную программу на нескольких универсальных планшетах Android. Как только служба не может быть найдена, я должен отключить оба устройства, а затем снова включить их. Использование быстрой перезагрузки не работает. Это обходной путь, я открыт для лучшего способа сделать это.   -  person Michael Perry    schedule 08.01.2017


Ответы (1)


Кажется, вы следовали примеру кода на сайте разработчиков Android, и есть две ошибки, которые блокируют нас:

  1. В методе public void onServiceFound(NsdServiceInfo service) код для проверки имени службы неверен. Насколько я понимаю, другое устройство в той же сети также может использовать то же имя службы, поэтому удалите блок кода if (service.getServiceName().equals(mServiceName)).
  2. То же самое происходит и в блоке кода public void onServiceResolved(NsdServiceInfo serviceInfo). пожалуйста, удалите блок кода if (serviceInfo.getServiceName().equals(mServiceName)).
person mxi1    schedule 28.11.2016
comment
Я согласен с вашими комментариями, но здесь проблема в том, что метод onServiceFound (служба NsdServiceInfo) не вызывается, даже если к сети подключено несколько устройств. Я использую SERVICE_TYPE — это _http._tcp. - person sandeepmaaram; 17.05.2017