Durch Network Service Discovery (NSD) erhält Ihre App Zugriff auf Dienste, die Geräte in einem lokalen Netzwerk bereitstellen. Zu den Geräten, die NSD unterstützen, gehören Drucker, Webcams, HTTPS-Server und andere Mobilgeräte.
Die NSD implementiert den DNS-basierten Diensterkennungsmechanismus (DNS-SD), der ermöglicht Ihrer Anwendung, Dienste anzufordern, indem Sie einen Diensttyp und den Namen angeben einer Geräteinstanz, die den gewünschten Diensttyp bereitstellt. DNS-SD ist die sowohl auf Android-Geräten als auch auf anderen mobilen Plattformen unterstützt werden.
Wenn Sie Ihrer Anwendung eine NSD hinzufügen, können Ihre Nutzer andere Geräte auf der lokalen Netzwerk, das die von deiner App angeforderten Dienste unterstützt. Dies ist nützlich für Eine Vielzahl von Peer-to-Peer-Anwendungen wie Dateifreigabe oder Multiplayer-Modus Gaming. Die NSD APIs von Android vereinfachen die Implementierung für diese Funktionen.
In dieser Lektion erfahren Sie, wie Sie eine Anwendung erstellen, die und suchen Sie nach Informationen. von anderen Anwendungen, die dasselbe tun. Schließlich erfahren Sie in dieser Lektion, um eine Verbindung zu derselben Anwendung herzustellen, die auf einem anderen Gerät ausgeführt wird.
Dienst im Netzwerk registrieren
Hinweis : Dieser Schritt ist optional. Wenn die App-Dienste nicht über das lokale Netzwerk zu übertragen, können Sie direkt zur im nächsten Abschnitt: Dienste im Netzwerk finden.
Erstellen Sie zuerst ein NsdServiceInfo
-Objekt, um Ihren Dienst im lokalen Netzwerk zu registrieren. Dieses Objekt stellt die Informationen bereit,
die andere Geräte im Netzwerk nutzen, wenn sie entscheiden, ob sie sich mit deinem
.
Kotlin
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) ... } }
Java
public void registerService(int port) { // Create the NsdServiceInfo object, and populate it. NsdServiceInfo serviceInfo = new NsdServiceInfo(); // The name is subject to change based on conflicts // with other services advertised on the same network. serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_nsdchat._tcp"); serviceInfo.setPort(port); ... }
Dieses Code-Snippet legt den Dienstnamen auf „NsdChat“ fest. Dienstname ist der Instanzname. Er ist der für andere Geräte im Netzwerk sichtbare Name. Der Name ist für jedes Gerät im Netzwerk sichtbar, das NSD verwendet, um nach lokale Dienstleistungen. Beachten Sie, dass der Name für jeden Dienst auf der und Android übernimmt die Konfliktlösung automatisch. Wenn Auf zwei Geräten im Netzwerk ist NsdChat installiert, eines der wird der Dienstname automatisch geändert, z. B. in „NsdChat“. (1)" beginnen.
Der zweite Parameter legt den Diensttyp fest und gibt das Protokoll und den Transport an. Ebene, die die Anwendung verwendet. Die Syntax lautet "_<Protokoll>._<Transportschicht>". Im Code-Snippet enthält, verwendet der Dienst ein HTTP-Protokoll, das über TCP ausgeführt wird. Eine Anwendung Wenn Sie einen Druckerdienst (z. B. einen Netzwerkdrucker) anbieten, wird der Diensttyp auf "_ipp._tcp" festlegen.
Hinweis : Die internationalen Zugewiesenen Nummern Die Behörde (IANA) verwaltet eine zentrale, autoritative Liste von Diensttypen, die von Diensterkennungsprotokollen wie NSD und Bonjour verwendet werden. Sie können die Liste über die IANA-Liste mit Dienstnamen und Portnummern. Wenn Sie einen neuen Diensttyp verwenden möchten, sollten Sie ihn reservieren, indem Sie IANA Ports and Service Registrierungsformular.
Vermeiden Sie es beim Festlegen des Ports für Ihren Dienst, ihn so hartzucodieren: in Konflikt mit anderen Anwendungen. Angenommen, Sie dass Ihre Anwendung immer Port 1337 verwendet, kann dies zu einem Konflikt mit Port 1337 führen. anderen installierten Anwendungen, die denselben Port verwenden. Verwenden Sie stattdessen die nächsten verfügbaren Port. Da diese Informationen von einem Dienst-Broadcast zu empfangen, ist es nicht erforderlich, dass der von Ihrer Anwendung verwendete Port Anwendungen bei der Kompilierung bekannt. Stattdessen können die Anwendungen erhalten Sie diese Informationen direkt, bevor Sie eine Verbindung zu Ihrem .
Wenn Sie mit Sockets arbeiten, können Sie wie folgt einen Socket initialisieren indem Sie den Wert auf 0 setzen.
Kotlin
fun initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = ServerSocket(0).also { socket -> // Store the chosen port. mLocalPort = socket.localPort ... } }
Java
public void initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = new ServerSocket(0); // Store the chosen port. localPort = serverSocket.getLocalPort(); ... }
Nachdem Sie das NsdServiceInfo
-Objekt definiert haben, müssen Sie die RegistrationListener
-Schnittstelle implementieren. Dieses
enthält Callbacks, die Android verwendet, um Ihre Anwendung des
Erfolg oder Misserfolg der Dienstregistrierung und -abmeldung.
Kotlin
private val registrationListener = object : NsdManager.RegistrationListener { override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) { // Save the service name. Android may have changed it in order to // resolve a conflict, so update the name you initially requested // with the name Android actually used. mServiceName = NsdServiceInfo.serviceName } override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Registration failed! Put debugging code here to determine why. } override fun onServiceUnregistered(arg0: NsdServiceInfo) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Unregistration failed. Put debugging code here to determine why. } }
Java
public void initializeRegistrationListener() { registrationListener = new NsdManager.RegistrationListener() { @Override public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { // Save the service name. Android may have changed it in order to // resolve a conflict, so update the name you initially requested // with the name Android actually used. serviceName = NsdServiceInfo.getServiceName(); } @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Registration failed! Put debugging code here to determine why. } @Override public void onServiceUnregistered(NsdServiceInfo arg0) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Unregistration failed. Put debugging code here to determine why. } }; }
Jetzt haben Sie alle Elemente, um Ihre Dienstleistung zu registrieren. Methode aufrufen
registerService()
Diese Methode ist asynchron. Code, der ausgeführt werden muss,
nachdem der Dienst registriert wurde, muss die Methode onServiceRegistered()
verwenden.
Kotlin
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) } nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager).apply { registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener) } }
Java
public void registerService(int port) { NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_http._tcp."); serviceInfo.setPort(port); nsdManager = Context.getSystemService(Context.NSD_SERVICE); nsdManager.registerService( serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener); }
Dienste im Netzwerk entdecken
Im Netzwerk wimmelt es nur so vor Leben, von den finsteren Netzwerkdruckern bis hin zu gedämpfte Netzwerk-Webcams bis hin zu den brutalen, wilden Kämpfen von Tic-Tac-Toe in der Nähe . Der Schlüssel, damit Ihre Anwendung dieses dynamische ist die Diensterkennung. Ihre Anwendung muss den Dienst überwachen Nachrichten an das Netzwerk senden, um zu sehen, welche Dienste verfügbar sind, und mit denen die Anwendung nicht funktionieren kann.
Die Diensterkennung, wie die Dienstregistrierung, umfasst zwei Schritte:
indem Sie einen Erkennungs-Listener mit den relevanten Callbacks einrichten und eine einzelne asynchrone
API-Aufruf an discoverServices()
.
Instanziieren Sie zuerst eine anonyme Klasse, die NsdManager.DiscoveryListener
implementiert. Das folgende Snippet zeigt eine
einfaches Beispiel:
Kotlin
// Instantiate a new DiscoveryListener private val discoveryListener = object : NsdManager.DiscoveryListener { // Called as soon as service discovery begins. override fun onDiscoveryStarted(regType: String) { Log.d(TAG, "Service discovery started") } override fun onServiceFound(service: NsdServiceInfo) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success$service") when { service.serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: ${service.serviceType}") service.serviceName == mServiceName -> // The name of the service tells the user what they'd be // connecting to. It could be "Bob's Chat App". Log.d(TAG, "Same machine: $mServiceName") service.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener) } } override fun onServiceLost(service: NsdServiceInfo) { // When the network service is no longer available. // Internal bookkeeping code goes here. Log.e(TAG, "service lost: $service") } override fun onDiscoveryStopped(serviceType: String) { Log.i(TAG, "Discovery stopped: $serviceType") } override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } }
Java
public void initializeDiscoveryListener() { // Instantiate a new DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() { // Called as soon as service discovery begins. @Override public void onDiscoveryStarted(String regType) { Log.d(TAG, "Service discovery started"); } @Override public void onServiceFound(NsdServiceInfo service) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success" + service); if (!service.getServiceType().equals(SERVICE_TYPE)) { // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: " + service.getServiceType()); } else if (service.getServiceName().equals(serviceName)) { // The name of the service tells the user what they'd be // connecting to. It could be "Bob's Chat App". Log.d(TAG, "Same machine: " + serviceName); } else if (service.getServiceName().contains("NsdChat")){ nsdManager.resolveService(service, resolveListener); } } @Override public void onServiceLost(NsdServiceInfo service) { // When the network service is no longer available. // Internal bookkeeping code goes here. 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); nsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } }; }
Die NSD API verwendet die Methoden in dieser Schnittstelle, um Ihre Anwendung über die Erkennung zu informieren gestartet wird, wenn er fehlschlägt und wenn Dienste gefunden und verloren werden (verloren bedeutet, nicht mehr verfügbar“). Dieses Snippet führt mehrere Prüfungen durch, wenn ein Dienst gefunden wird.
- Der Dienstname des gefundenen Dienstes wird mit dem Dienstnamen verglichen Name des lokalen Dienstes, um festzustellen, ob das Gerät gerade seinen eigenen abgerufen hat Broadcast (gültig ist).
- Der Diensttyp wurde überprüft, um zu bestätigen, dass es sich um App eine Verbindung herstellen kann.
- Der Dienstname wird überprüft, um die Verbindung zum richtigen .
Die Überprüfung des Dienstnamens ist nicht immer erforderlich und nur relevant, wenn Sie eine Verbindung zu einer bestimmten Anwendung herstellen möchten. Zum Beispiel könnte die Anwendung nur eine Verbindung zu eigenen Instanzen herstellen möchte, die auf anderen Geräten ausgeführt werden. Wenn die Anwendung eine Verbindung zu einem Netzwerkdrucker herstellen möchte, reicht es aus, dass der Diensttyp ist „_ipp._tcp“.
Rufen Sie nach dem Einrichten des Listeners discoverServices()
auf und übergeben Sie den Diensttyp
das Ihre Anwendung suchen soll,
das zu verwendende Discovery-Protokoll und
den Sie gerade erstellt haben.
Kotlin
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
Java
nsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
Verbindung zu Diensten im Netzwerk herstellen
Wenn Ihre Anwendung im Netzwerk einen Dienst findet, zu dem eine Verbindung hergestellt werden kann,
müssen zuerst die Verbindungsinformationen für diesen Dienst mithilfe der Methode
resolveService()
-Methode.
Implementiere eine NsdManager.ResolveListener
, die an dieses übergeben wird
und verwenden Sie, um ein NsdServiceInfo
-Element abzurufen, das
die Verbindungsinformationen abrufen.
Kotlin
private val resolveListener = object : NsdManager.ResolveListener { override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed: $errorCode") } override fun onServiceResolved(serviceInfo: NsdServiceInfo) { Log.e(TAG, "Resolve Succeeded. $serviceInfo") if (serviceInfo.serviceName == mServiceName) { Log.d(TAG, "Same IP.") return } mService = serviceInfo val port: Int = serviceInfo.port val host: InetAddress = serviceInfo.host } }
Java
public void initializeResolveListener() { resolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed: " + errorCode); } @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { Log.e(TAG, "Resolve Succeeded. " + serviceInfo); if (serviceInfo.getServiceName().equals(serviceName)) { Log.d(TAG, "Same IP."); return; } mService = serviceInfo; int port = mService.getPort(); InetAddress host = mService.getHost(); } }; }
Sobald der Dienst gelöst ist, erhält Ihre Anwendung detaillierte Dienstinformationen, einschließlich IP-Adresse und Portnummer. Das ist alles müssen Sie eine eigene Netzwerkverbindung zum Dienst herstellen.
Registrierung des Dienstes beim Schließen der Anwendung aufheben
Es ist wichtig, NSD zu aktivieren und zu deaktivieren die während der Laufzeit der App Lebenszyklus. Wenn Sie die Registrierung Ihrer Anwendung aufheben, wenn sie beendet wird, andere Anwendungen nicht den Eindruck bekommen, dass sie noch aktiv sind, und versuchen, . Außerdem ist die Diensterkennung ein teurer Vorgang und sollte gestoppt werden wenn die übergeordnete Aktivität pausiert wird, und wieder aktiviert, wenn die Aktivität wurde(n) fortgesetzt. Lebenszyklusmethoden der Hauptaktivität überschreiben und Code einfügen um die Übertragung und Erkennung von Diensten zu starten und zu beenden.
Kotlin
// In your application's Activity override fun onPause() { nsdHelper?.tearDown() super.onPause() } override fun onResume() { super.onResume() nsdHelper?.apply { registerService(connection.localPort) discoverServices() } } override fun onDestroy() { nsdHelper?.tearDown() connection.tearDown() super.onDestroy() } // NsdHelper's tearDown method fun tearDown() { nsdManager.apply { unregisterService(registrationListener) stopServiceDiscovery(discoveryListener) } }
Java
// In your application's Activity @Override protected void onPause() { if (nsdHelper != null) { nsdHelper.tearDown(); } super.onPause(); } @Override protected void onResume() { super.onResume(); if (nsdHelper != null) { nsdHelper.registerService(connection.getLocalPort()); nsdHelper.discoverServices(); } } @Override protected void onDestroy() { nsdHelper.tearDown(); connection.tearDown(); super.onDestroy(); } // NsdHelper's tearDown method public void tearDown() { nsdManager.unregisterService(registrationListener); nsdManager.stopServiceDiscovery(discoveryListener); }