This is an old revision of the document!
Laborator 09. Implementarea Serviciilor de Rețea în Android
În Android, prin intermediul serviciilor, sunt puse la dispoziție funcționalități care pot fi accesate de către dispozitivele care se găsesc în aceeași rețea locală. De obicei, o astfel de abordare se folosește pentru stabilirea de conexiuni punct la punct peste care pot fi dezvoltare jocuri la care pot participa mai mulți utilizatori, aplicații de partajare a unor resurse sau pentru transmiterea de mesaje. Totodată, pot fi expuse și servicii ale unor alte dispozitive din cadrul rețelei locale cum ar fi: calculatoare, imprimante, televizoare, ceasuri inteligente, acestea putând fi astfel accesate la distanță.
Serviciile pot fi implementate folosind două variante:
- Android Network Service Discovery (NSD), un protocol integrat în Android începând cu nivelul de API 16 (Jelly Bean), pentru implementarea de servicii disponibile în rețeaua locală;
- JmDNS, un proiect open-source care își propune implementarea în Java a unor funcționalități legate de proiectarea și dezvoltarea de servicii disponibile în rețeaua locală, fără a realiza nici un fel de configurări legate de infrastructura de comunicație.
Operațiile utilizate în implementarea serviciilor de rețea sunt:
- configurarea diferiților parametri (pregătirea mediului de lucru);
- înregistrarea unui serviciu, prin care celelalte dispozitive din rețeaua locală pot afla detalii cu privire la funcționalitatea oferită (tip de serviciu, adresă, port, descriere);
- descoperirea unui serviciu, prin care un dispozitiv este informat cu privire la serviciile care pot fi accesate în rețeaua locală, filtrându-le în funcție de denumire și tip;
- rezolvarea unui serviciu, prin care sunt identificate adresa și portul la care trebuie realizată o conexiune în vederea exploatării funcționalității pe care acesta o pune la dispoziție.
Tipuri de Servicii
Cele mai multe servicii accesibile prin rețeaua locală sunt descrise prin intermediul unui tip care are de obicei forma _<protocol_nivel_aplicatie>._<protocol_nivel_transport>., unde:
<protocol_nivel_aplicatie>poate fi standard sau definit de utilizator;<protocol_nivel_transport>este de regulătcpsauudp(sau variații ale acestora).
Se poate consulta lista cu tipurile de servicii rezervate, gestionată de IANA (Autoritatea Internațională pentru Numere Alocate). Unele tipuri de servicii au definite și porturile pe care pot fi accesate.Pentru rezervarea unui astfel de tip de serviciu, este necesară o solicitare prealabilă, care poate fi aprobată sau respinsă, după caz.
Pentru Android NSD, pentru cele mai multe servicii nespecifice, se poate folosi tipul _http._tcp. (se folosește transferul de date prin HTTP folosind protocolul de transport TCP).
În cazul JmDNS, trebuie să se precizeze faptul că serviciul rulează local, definindu-se un tip corespunzător aplicației care implementează funcționalitatea respectivă (_<denumire_aplicatie>._tcp.local.).
Configurare
Inițializarea mediului de lucru presupune instanțierea unor obiecte care gestionează operațiile ce pot fi realizate la nivelul serviciilor de rețea, respectiv a unor obiecte ascultător pentru evenimentele care pot surveni în cadrul acestora.
Android NSD
Configurarea Android NSD presupune obținerea unei referințe către un obiect de tipul NsdManager, care oferă funcționalități referitoare la gestiunea serviciilor existente doar în cadrul rețelei locale.
NsdManager nsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
API-ul pe care îl pune la dispoziție un astfel de obiect este asincron, astfel încât metodele apelate în cadrul claselor ascultător pentru diferite evenimente (înregistrare, descoperire, rezolvare) sunt executate în contextul unor fire de execuție dedicate, așa cum trebuie procedat în condițiile unor operații ce implică comunicația prin rețea.
Metodele pe care le implementează un obiect de tipul NsdManager sunt legate de operațiile ce pot fi realizate cu serviciile accesibile în cadrul rețelei locale:
- înregistrare
- registerService(NsdServiceInfo, int, NsdManager.RegistrationListener) - folosită pentru înregistrarea unui serviciu, care să poată fi disponibil ulterior în cadrul rețelei locale;
- unregisterService(NsdManager.RegistrationListener) - folosită pentru deînregistrarea unui serviciu, astfel încât acesta să nu mai poată fi accesat, atunci când nu mai este necesar sau aplicația Android este distrusă.
- descoperire
- discoverServices(String, int, NsdManager.DiscoveryListener) - folosită pentru pornirea descoperirii de servicii accesibile în rețeaua locală, operație care va fi realizată permanent, până când se va specifica altfel (explicit), afectând resurse precum transferul de informații prin rețeaua locală (lățimea de bandă) și bateria;
- stopServiceDiscovery(NsdManager.DiscoveryListener) - folosită pentru oprirea descoperirii de servicii, atunci când acesta nu mai este necesară sau aplicația Android este întreruptă temporar.
- rezolvare - resolveService(NsdServiceInfo, NsdManager.ResolveListener), pentru a identifica parametrii de conexiune ai unui serviciu (adresă și port).
Se observă că de regulă aceste metode primesc parametrii de tip:
- NsdServiceInfo - în care sunt stocate perechi de tipul (atribut, valoare) cu privire la serviciul disponibil în rețea:
- denumire;
- tip;
- adresă;
- port.
- ascultător pentru diferite evenimente legate de operațiile cu serviciile accesibile în rețea (înregistrare, descoperire, rezolvare), fiecare definind metode care descriu comportamentul pentru fiecare rezultat posibil al acestora.
În fișierul AndroidManifest.xml, singurele permisiuni care trebuie oferite aplicației sunt cele legate de accesul la rețeaua locală:
- AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ro.pub.cs.systems.pdsd.lab09.chatservice" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <!-- ... --> </manifest>
JmDNS
Întrucât versiunea curentă a JmDNS (3.4.1) oferă o bibliotecă sub forma unei arhive .jar care nu poate fi procesată în momentul în care este transformată în formatul .dex, este necesar ca aceasta să fie prelucrată, în sensul menținerii acelor clase care sunt strict necesare pentru gestiunea serviciilor de rețea, și anume cele din pachetul javax.jmdns.
student@pdsd2015:~$ jar xf jmdns.jar student@pdsd2015:~$ jar cfm jmdns.jar META-INF/MANIFEST.MF javax/
JmDNS folosește pachete de tip multicast pentru a gestiona serviciile disponibile în rețea. Politica Android este de a dezactiva implicit astfel de transferuri, pentru a optimiza bateria, motiv pentru care această funcționalitate trebuie activată temporar, doar pe parcursul aplicației Android. În acest sens, trebuie obținut mutext-ul corespunzător operațiilor de acest tip, care va fi eliberat ulterior:
- ChatActivity.java
public class ChatActivity extends Activity { // ... protected WifiManager wifiManager = null; @Override protected void onCreate(Bundle state) { super.onCreate(state); // ... WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE); multicastLock = wifiManager.createMulticastLock(Constants.TAG); multicastLock.setReferenceCounted(true); multicastLock.acquire(); } @Override protected void onDestroy() { super.onDestroy(); // ... if (multicastLock != null) { multicastLock.relase(); multicastLock = null; } } // ... }
Configurarea JmDNS presupune crearea unei instanțe a unui obiect de tipul JmDNS, care oferă funcționalități referitoare la gestiunea serviciilor existente doar în cadrul rețelei locale. Se utilizează metoda statică create(InetAddress, String), care primește ca parametri:
- adresa mașinii, obținută prin intermediul metodei
getIpAddress()apelată pe obiectulConnectionInfoasociat obiectului care gestoniează interfața pentru comunicația prin intermediul rețelei fără fir; - denumirea mașinii (determinată pe baza adresei, prin rezoluție inversă).
try { WifiManager wifiManager = ((ChatActivity)context).getWifiManager(); InetAddress address = InetAddress.getByAddress( ByteBuffer.allocate(4).putInt( Integer.reverseBytes(wifiManager.getConnectionInfo().getIpAddress()) ).array() ); String name = address.getHostName(); Log.i(Constants.TAG, "address = " + address + " name = " + name); jmDns = JmDNS.create(address, name); } catch (IOException ioException) { Log.e(Constants.TAG, "An exception has occurred: " + ioException.getMessage()); if (Constants.DEBUG) { ioException.printStackTrace(); } }
JmDNS trebuie să se realizeze pe firul de execuție al comunicației prin rețea, în caz contrar generându-se o excepție de tipul android.os.NetworkOnMainThreadException.
API-ul pe care îl pune la dispoziție un astfel de obiect este asincron, astfel încât metodele apelate în cadrul claselor ascultător pentru diferite evenimente (înregistrare, descoperire, rezolvare) sunt executate în contextul unor fire de execuție dedicate, așa cum trebuie procedat în condițiile unor operații ce implică comunicația prin rețea.
- înregistrare
- registerService(ServiceInfo) - folosită pentru înregistrarea unui serviciu, care să poată fi disponibil ulterior în cadrul rețelei locale;
- unregisterService(ServiceInfo) sau unregisterAllServices()- folosită pentru deînregistrarea unui serviciu, astfel încât acesta să nu mai poată fi accesat, atunci când nu mai este necesar sau aplicația Android este distrusă.
- descoperire
- addServiceListener(String, ServiceListener) - folosită pentru pornirea descoperirii de servicii accesibile în rețeaua locală, operație care va fi realizată permanent, până când se va specifica altfel (explicit), afectând resurse precum transferul de informații prin rețeaua locală (lățimea de bandă) și bateria; vor fi monitorizate doar serviciile de un anumit tip;
- removeServiceListener(ServiceListener) - folosită pentru oprirea descoperirii de servicii de un anumit tip, atunci când acesta nu mai este necesară sau aplicația Android este întreruptă temporar.
- rezolvare - requestServiceInfo(String, String), pentru a identifica parametrii de conexiune (adresă și port) ai unui serviciu pentru care se cunoaște tipul și denumirea.â
Se observă că de regulă aceste metode primesc parametrii de tip:
- ServiceInfo - în care sunt stocate perechi de tipul (atribut, valoare) cu privire la serviciul disponibil în rețea:
- denumire;
- tip / subtip;
- adresă / denumire dispozitiv care găzduiește serviciul;
- port pe care poate fi accesat serviciul;
- prioritate;
- protocol
- date
- URL.
- ascultător pentru diferite evenimente legate de operațiile cu serviciile accesibile în rețea (înregistrare, descoperire, rezolvare), fiecare definind metode care descriu comportamentul pentru fiecare rezultat posibil al acestora.
Resusele asociate obiectului de tip JmDNS trebuie eliberate în momentul în care acesta nu mai este necesar (aplicația Android este distrusă):
try { if (jmDns != null) { jmDns.close(); jmDns = null; } } catch (IOException ioException) { Log.e(Constants.TAG, "An exception has occurred: " + ioException.getMessage()); if (Constants.DEBUG) { ioException.printStackTrace(); } }
În fișierul AndroidManifest.xml, permisiunile care trebuie oferite aplicației vizează:
- accesul la Internet;
- schimbarea politicii cu privire la procesarea pachetelor de tip multi-cast (implicit dezactivate, pentru a optimiza consumul de energie);
- accesul la starea rețelei fără fir;
- accesul la starea rețelei cu fir.
- AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ro.pub.cs.systems.pdsd.lab09.chatservice" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- ... --> </manifest>
Înregistrarea / Deînregistrarea unui Serviciu
Android NSD
Pentru înregistrarea unui serviciu, se apelează metoda registerService(NsdServiceInfo, int, NsdManager.RegistrationListener) din clasa NsdManager, ulterior serviciul putând fi accesat din cadrul altor mașini fizice / dispozitive mobile. Aceasta primește ca parametri:
- un obiect
NsdServiceInfo, ce reține informații precum denumirea și tipul serviciului, adresa și portul mașinii / dispozitivului pe care va fi disponibil;
ServerSocket astfel instanțiat sau pot fi folosite valori obținute de la utilizator:
ServerSocket serverSocket = new ServerSocket(0); InetAddress address = serverSocket.getInetAddress(); int port = serverSocket.getLocalPort();
Valoarea 0 a parametrului din constructorul obiectului ServerSocket indică faptul că se va folosi un port libere, aleator. O astfel de abordare este de preferat, întrucât se evită eventualele conflicte cu privire la porturile ocupate.
- protocolul, în acest caz folosindu-se
NsdManager.PROTOCOL_DNS_SD; - un obiect ascultător de tipul
NsdManager.RegistrationListener, care trebuie să implementeze metodele:- onServiceRegistered(NsdServiceInfo), apelată în mod automat în momentul în care înregistrarea serviciului a fost realizată cu succes;
- onRegistrationFailed(NsdServiceInfo, int), apelată în mod automat în momentul în care înregistrarea serviciului a eșuat, oferindu-se și un cod de eroare pentru depanarea cauzei.
Pentru deînregistrarea unui serviciu, se apelează metoda unregisterService(NsdManager.RegistrationListener) din clasa NsdManager. Aceasta primește ca parametru un obiect ascultător de tipul NsdManager.RegistrationListener, care trebuie să implementeze metodele:
- onServiceUnegistered(NsdServiceInfo), apelată în mod automat în momentul în care deînregistrarea serviciului a fost realizată cu succes;
- onUnregistrationFailed(NsdServiceInfo, int), apelată în mod automat în momentul în care deînregistrarea serviciului a eșuat, oferindu-se și un cod de eroare pentru depanarea cauzei.
public void registerNetworkService() throws Exception { chatServer = new ChatServer(this); ServerSocket serverSocket = chatServer.getServerSocket(); if (serverSocket == null) { throw new Exception("Could not get server socket"); } chatServer.start(); NsdServiceInfo nsdServiceInfo = new NsdServiceInfo(); nsdServiceInfo.setServiceName(Constants.SERVICE_NAME); nsdServiceInfo.setServiceType(Constants.SERVICE_TYPE); nsdServiceInfo.setHost(serverSocket.getInetAddress()); nsdServiceInfo.setPort(serverSocket.getLocalPort()); nsdManager.registerService( nsdServiceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener ); } public void unregisterNetworkService() { nsdManager.unregisterService(registrationListener); chatServer.stopThread(); // ... }
De regulă, metodele obiectului de tip NsdManager.RegistrationListener nu vor avea alt rol cu excepția jurnalizării evenimentelor respective, mai ales atunci când operațiile de înregistrare / deînregistrare eșuează.
În momentul în care înregistrarea s-a realizat cu succes, se va reține denumirea serviciului, fapt important întrucât în situația în care în rețeaua locală există un alt serviciu cu aceeași denumire, sistemul de operare Android va trata o astfel de situație prin atașarea unui indice (x), indicând al câtelea serviciu duplicat a fost identificat.
În momentul în care deînregistrarea s-a realizat cu succes, nu este necesar să se realizeze nici o operație.
NsdManager.RegistrationListener registrationListener = new RegistrationListener() { @Override public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) { serviceName = nsdServiceInfo.getServiceName(); } @Override public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int errorCode) { Log.e(Constants.TAG, "An exception occured while registering the service: " + errorCode); } @Override public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) { } @Override public void onUnregistrationFailed(NsdServiceInfo nsdServiceInfo, int errorCode) { Log.e(Constants.TAG, "An exception occured while unregistering the service: " + errorCode); } };
JmDNS
Pentru înregistrarea unui serviciu, se apelează metoda registerService(ServiceInfo) din clasa JmDNS, ulterior serviciul putând fi accesat din cadrul altor mașini fizice / dispozitive mobile.
Pentru deînregistrarea unui serviciu, se poate apela una din metodele unregisterService(ServiceInfo), respectiv unregisterAllServices()din clasa JmDNS.
ServiceInfo, ce reține informații precum denumirea și tipul serviciului, adresa și portul mașinii / dispozitivului pe care va fi disponibil (ce pot fi preluate, din cadrul unui obiect de tip ServerSocket).
public void registerNetworkService() throws Exception { chatServer = new ChatServer(this); ServerSocket serverSocket = chatServer.getServerSocket(); if (serverSocket == null) { throw new Exception("Could not get server socket"); } chatServer.start(); ServiceInfo serviceInfo = ServiceInfo.create( Constants.SERVICE_TYPE, Constants.SERVICE_NAME, port, Constants.SERVICE_DESCRIPTION ); if (jmDns != null && serviceInfo != null) { serviceName = serviceInfo.getName(); jmDns.registerService(serviceInfo); } } public void unregisterNetworkService() { if (jmDns != null) { jmDns.unregisterAllServices(); } chatServer.stopThread(); // ... }
Descoperirea Serviciilor Accesibile
Operațiile de pornire / oprire a descoperirii serviciilor disponibile trebuie să aibă în vedere resursele afectate precum și impactul asupra altor funcționalități cum ar fi viteza de transfer prin rețea, respectiv autonomia.
De regulă, pornirea operației de descoperire a serviciilor disponibile este realizată pe metoda onResume(), adică din momentul în care activitatea este vizibilă.
Similar, oprirea operației de descoperire a serviciilor disponibile este realizată pe metoda onPause(), adică din momentul în care activitatea nu este vizibilă.
Totodată, este recomandat să se pună la dispoziția utilizatorilor elemente în cadrul interfeței grafice prin intermediul cărora aceste operații să poată fi controlate prin interacțiunea cu cei care folosesc aplicația Android.
Android NSD
Pornirea operației de descoperire a serviciilor disponibile se face prin intermediul metodei discoverServices(String, int, NsdManager.DiscoveryListener) din clasa NsdManager care primește ca parametri:
- tipul de serviciu;
- protocolul, în acest caz folosindu-se
NsdManager.PROTOCOL_DNS_SD; - un obiect ascultător de tipul
NsdManager.DiscoveryListener, care trebuie să implementeze metodele:- onDiscoveryStarted(String) - apelată în mod automat dacă pornirea operației de căutare a serviciilor a fost realizată cu succes;
- onStartDiscoveryFailed(String, int) - apelată în mod automat dacă pornirea operației de căutare a serviciilor a eșuat, oferindu-se și un cod de eroare care poate fi folosit în scopuri de depanare.
Oprirea operației de descoperire a serviciilor disponibile se face prin intermediul metodei stopServiceDiscovery(NsdManager.DiscoveryListener) din clasa NsdManager care primește ca parametru un obiect ascultător de tipul NsdManager.DiscoveryListener, care trebuie să implementeze metodele:
- onDiscoveryStopped(String) - apelată în mod automat dacă oprirea operației de căutare a serviciilor a fost realizată cu succes;
- onStopDiscoveryFailed(String, int) - apelată în mod automat dacă oprirea operației de căutare a serviciilor a eșuat, oferindu-se și un cod de eroare care poate fi folosit în scopuri de depanare.
public void startNetworkServiceDiscovery() { nsdManager.discoverServices(Constants.SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener); } public void stopNetworkServiceDiscovery() { nsdManager.stopServiceDiscovery(discoveryListener); // ... }
Pentru obiectul de tip NsdManager.DiscoveryListener trebuie implementate și metodele apelate în mod automat în momentul în care un serviciu este găsit, respectiv este pierdut:
- onServiceFound(NsdServiceInfo) - se verifică parametrii serviciului descoperit (tip și denumire), putându-se întâlni următoarele situații:
- tip de serviciu necunoscut (cu toate că descoperirea implică filtrarea după un tip de servicii specific);
- descoperirea serviciului oferit de mașina curentă / dispozitivul curent - se realizează comparația dintre denumirea serviciului găsit și denumirea serviciului curent;
- descoperirea unui serviciu oferit de o altă mașină / un alt dispozitiv (se poate folosi un șablon pe denumirea serviciului) - se trece la rezolvarea serviciului respectiv (prin invocarea metodei
resolveService(NsdManager, NsdManager.ResolveListener)din cadrul obiectului de tipNsdManager.
- onServiceLost(NsdServiceInfo) - se gestionează corespunzător lista de servicii descoperite.
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() { @Override public void onDiscoveryStarted(String serviceType) { Log.i(Constants.TAG, "Service discovery started: " + serviceType); } @Override public void onServiceFound(NsdServiceInfo nsdServiceInfo) { Log.i(Constants.TAG, "Service found: " + nsdServiceInfo); if (!nsdServiceInfo.getServiceType().equals(Constants.SERVICE_TYPE)) { Log.i(Constants.TAG, "Unknown Service Type: " + nsdServiceInfo.getServiceType()); } else if (nsdServiceInfo.getServiceName().equals(serviceName)) { Log.i(Constants.TAG, "The service running on the same machine has been discovered: " + serviceName); } else if (nsdServiceInfo.getServiceName().contains(Constants.SERVICE_NAME_SEARCH_KEY)) { nsdManager.resolveService(nsdServiceInfo, resolveListener); } } @Override public void onServiceLost(final NsdServiceInfo nsdServiceInfo) { Log.i(Constants.TAG, "Service lost: " + nsdServiceInfo); ArrayList<NetworkService> discoveredServices = chatNetworkServiceFragment.getDiscoveredServices(); NetworkService networkService = new NetworkService( nsdServiceInfo.getServiceName(), (nsdServiceInfo.getHost() != null) ? nsdServiceInfo.getHost().toString() : null, nsdServiceInfo.getPort(), -1 ); if (discoveredServices.contains(networkService)) { int index = discoveredServices.indexOf(networkService); discoveredServices.remove(index); } chatNetworkServiceFragment.setDiscoveredServices(discoveredServices); // ... } @Override public void onDiscoveryStopped(String serviceType) { Log.i(Constants.TAG, "Service discovery stopped: " + serviceType); } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { Log.e(Constants.TAG, "Service discovery start failed - Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.e(Constants.TAG, "Service discovery stop failed - Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } };
JmDNS
public void startNetworkServiceDiscovery() { if (jmDns != null && serviceListener != null) { jmDns.addServiceListener(Constants.SERVICE_TYPE, serviceListener); } } public void stopNetworkServiceDiscovery() { if (jmDns != null && serviceListener != null) { jmDns.removeServiceListener(Constants.SERVICE_TYPE, serviceListener); } // ... }
ServiceListener serviceListener = new ServiceListener() {
// ...
@Override
public void serviceAdded(ServiceEvent serviceEvent) {
if (!serviceEvent.getType().equals(Constants.SERVICE_TYPE)) {
Log.i(Constants.TAG, "Unknown Service Type: " + serviceEvent.getType());
} else if (serviceEvent.getName().equals(serviceName)) {
Log.i(Constants.TAG, "The service running on the same machine has been discovered: " + serviceName);
} else if (serviceEvent.getName().contains(Constants.SERVICE_NAME_SEARCH_KEY)) {
Log.i(Constants.TAG, "The service should be resolved now: " + serviceName);
jmDns.requestServiceInfo(serviceEvent.getType(), serviceEvent.getName(), 1);
}
}
@Override
public void serviceRemoved(final ServiceEvent serviceEvent) {
ServiceInfo serviceInfo = serviceEvent.getInfo();
if (serviceInfo == null) {
Log.e(Constants.TAG, "Service Info for Service is null!");
return;
}
String[] hosts = serviceInfo.getHostAddresses();
String host = null;
if (hosts.length != 0) {
host = hosts[0];
if(host.startsWith("/")) {
host = host.substring(1);
}
}
int port = serviceInfo.getPort();
// ...
ArrayList<NetworkService> discoveredServices = chatNetworkServiceFragment.getDiscoveredServices();
NetworkService networkService = new NetworkService(serviceEvent.getName(), host, port, -1);
if (discoveredServices.contains(networkService)) {
int index = discoveredServices.indexOf(networkService);
discoveredServices.remove(index);
}
chatNetworkServiceFragment.setDiscoveredServices(discoveredServices);
}
};
Rezolvarea Serviciilor Descoperite Anterior
Android NSD
JmDNS
Gestiunea unei Conexiuni către Servicii Disponibile
Android NSD
JmDNS
Activitate de Laborator
Resurse Utile
Connecting Devices Wirelessly
Quick Tutorial on Using Jmdns on Android
How to discover device (or service) on Android?
Service discovery using JmDNS in Eclipse : Wifistatemachine errors
Service Name and Transport Protocol Port Number Registry
http://sourceforge.net/projects/jmdns/
