05_Android_Connectivite_WebServices - JFOD

publicité
Connectivité, Web Services
Orienté clients/serveur TCP et Bluetooth
jean-michel Douin, douin au cnam point fr
version : 3 Décembre 2015
Notes de cours
Avertissement :
Android_Clients_Serveur
1
Bibliographie utilisée
http://developer.android.com/resources/index.html
http://developer.android.com/reference/android/os/AsyncTask.html
Un ensemble de tutoriels à lire
http://www.vogella.de/android.html
http://www.vogella.de/articles/AndroidPerformance/article.html
Android_Clients_Serveur
2
Sommaire
• Clients et serveurs TCP
– Un Client, une requête
– Serveur TCP (HTTP,…)
– Clients Bluetooth
• Annexes, cf. NFP121
– Format XML,
• API SAX
– Format JSON
• json.org
Android_Clients_Serveur
3
Client et serveur
• Serveurs TCP
– Exemples
– Requête
Android_Clients_Serveur
4
Serveurs
• En mode TCP
• Appels distants en mode TCP/IP
– Point à point avec accusé de réception
– telnet, ftp, http, …
Android_Clients_Serveur
5
URL …
• URL Uniform Resource Locator
une adresse sur internet
– http://jfod.cnam.fr
– http le protocole
– //jfod.cnam.fr le nom de la ressource
– http://jfod.cnam.fr:8999/ds2438/mesures.html
Android_Clients_Serveur
6
Exemples clients / serveurs
protocole
Client1
Client2
Client3
Serveur
1. Le client s’adresse au serveur
– Établit une connexion
2. Le serveur satisfait ses clients
– Mode synchrone, analogue à l’appel d’une méthode locale
Android_Clients_Serveur
7
Appels distants protocole « maison »
maison
JVM
Client1
JVM
Client2
Client3
serveur
• Le contexte
– Client Java, ou autres
– Serveur en java ou autre
– maison : //serveur/….
Android_Clients_Serveur
8
Appels distants protocole http
http
JVM
Client1
Client2
un
navigateur
JVM
serveur
• Le contexte
– Client Java(application comme applette), ou autres
– Un navigateur
– Serveur en java , ou autres
• http: //serveur/index.html
• Standard, universel …
Android_Clients_Serveur
9
Implémentation en Java
• Paquetage java.net
– Principales classes
•
•
•
•
•
ServerSocket
Socket
InetAddress
URLConnection
…
– Quelques lignes de sources suffisent …
Android_Clients_Serveur
10
usage de java.net
TCP/IP
JVM
JVM
Client1
Serveur
• 2 classes essentielles
Côté Serveur
– java.net.ServerSocket
• Méthode accept() sur une instance de la classe ServerSocket
Côté Client
– java.net.Socket, java.net.SocketAddress
• Envoi sur une instance de la classe Socket de données
Android_Clients_Serveur
11
Connexion / Principes
port
port
port
JVM
JVM
Serveur
Client1
•
Le Serveur attend une requête sur son port
– ServerSocket server = new ServerSocket(port)
– Socket socket = server.accept();
•
Dès la connexion établie,
– une instance de la classe Socket est engendrée sur un port temporaire
•
Établir une connexion par le client est effectuée par
– Socket s = new Socket(Serveur, port)
Android_Clients_Serveur
12
2 exemples
•
Serveur et client
1. Au protocole « maison »
•
•
Le serveur ne connaît que la commande « parle » et répond « bonjour »
Tout autre commande est ignorée !
2. Au protocole http
•
•
Android_Clients_Serveur
Seule la méthode GET /index.html HTTP1.0 est possible
Un sous-ensemble donc …
13
Exemple 1
JVM
maison: //serveur
parle
Client1
JVM
Serveur
bonjour
– Au protocole « maison »
•
•
Le serveur ne connaît que la commande « parle » et répond « bonjour »
Tout autre commande est ignorée !
– Client java ou autre
Android_Clients_Serveur
14
Un serveur avec un protocole « maison »
public class Serveur{
public static void main(String[] args) throws Exception{
ServerSocket serveur = new ServerSocket(5000);
while(true) {
Socket socket = serveur.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String cmd = in.readLine();
// parle !!!
DataOutputStream out = new DataOutputStream( socket.getOutputStream());
if(cmd.equals("parle")){
out.write("bonjour\n".getBytes());
}else{
out.write("commande inconnue ?\n".getBytes());
}
socket.close();
}
}
}
Android_Clients_Serveur
15
Le client « maison »
public class Client{
public static void main(String[] args) throws Exception{
Socket socket = new Socket("vivaldi.cnam.fr", 5000);
DataOutputStream out= new DataOutputStream( socket.getOutputStream());
out.write(args[0].getBytes());
out.write("\n".getBytes());
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
System.out.println(in.readLine());
socket.close();
}
}
Android_Clients_Serveur
16
Un client « maison », telnet
• telnet localhost 5000
– parle // frappe sans écho
• petit outil utile : tcpview
Android_Clients_Serveur
17
Exemple 2
• Le protocole HTTP
– Les méthodes GET, POST, ….
• Mise en œuvre / démo
– Usage d’un client telnet sur un site existant
– Une application Java cliente
– Un serveur en java
Android_Clients_Serveur
18
Protocole HTTP
• HyperText Transfer Protocol
– Au dessus de TCP
• Les Méthodes
– GET /index.html
– HEAD
– POST
–
–
–
–
HTTP/1.0
PUT
DELETE
TRACE
CONNECT
– Voir http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Android_Clients_Serveur
19
Côté serveur, méthode accept
ServerSocket listen = new ServerSocket(HTTP_PORT);
while(!stopped()){
try{
Socket socket = listen.accept();
handleRequest(socket);
}catch(Exception e){
}
}
listen.close();
}
listen.accept() est bloquant : au moins un client.
Android_Clients_Serveur
20
Exemple minimaliste !
• Un serveur Web au complet
– Un seul client, une seule requête !
• Extrait de
Android_Clients_Serveur
21
OneShot Httpd by Hendrik, j2se
public class OneShotHttpd {
protected static File docRoot;
public final static int HTTP_PORT = 8080;
public static void main(String argv[]){
try{
docRoot = new File(".");
ServerSocket listen = new ServerSocket(HTTP_PORT);
Socket client = listen.accept();
BufferedReader is = new BufferedReader(new
InputStreamReader(client.getInputStream()));
DataOutputStream os = new DataOutputStream(client.getOutputStream());
String request = is.readLine();
StringTokenizer st = new StringTokenizer(request);
if((st.countTokens() == 3) && st.nextToken().equals("GET")){
String filename = docRoot.getPath() + st.nextToken();
if(filename.endsWith("/") || filename.equals(""))
filename += "index.html";
File file = new File(filename);
sendDocument(os,file);
} else
System.err.println("400 Bad Request");
is.close(); os.close(); client.close();
}catch(IOException ioe){
System.err.println("Error: " + ioe.toString());
}}
Android_Clients_Serveur
22
OneShot « envoi du document »
public static void sendDocument(DataOutputStream out, File file) throws
IOException{
try{
BufferedInputStream in = new BufferedInputStream(
new FileInputStream(file));
byte[] buf = new byte[1024];
int len;
while((len = in.read(buf,0,1024)) != -1)
{
out.write(buf,0,len);
}
in.close();
}
catch(FileNotFoundException fnfe)
{
System.err.println("404 Not Found");
}
}
}
Android_Clients_Serveur
23
OneShot avec Android
• AsyncTask<Params, Progress, Result>
Rappel
– Réalise une encapsulation d’un Thread et de l’accès à l’écran
• onPreExecute()
– Préambule, l’UI exécute cette méthode
• Void doInBackground(String… s){
OneShotHttpd.main(s);
• }
• onProgressUpdate(Progress…p)
– Mise à jour de l’UI à la suite de l’appel de publishProgress
• onPostExecute(Result)
– Mise à jour de l’UI à la fin de la méthode doInBackground
Android_Clients_Serveur
24
Côté serveur, un thread à chaque requête
ServerSocket listen = new ServerSocket(HTTP_PORT);
while(!stopped()){
try{
new Connection(listen.accept());
}catch(Exception e){
}
}
// création d’une instance
listen.close();
}
Chaque requête engendre la création d’une instance de la classe Connection
Et chaque instance créée engendre à son tour un « Thread »
Android_Clients_Serveur
25
Côté serveur, à chaque Connection un Thread
public class Connexion extends Thread{
…
public Connexion(Socket s){
this.s = s; start();
}
public void run(){
try{
BufferedReader is = new BufferedReader(
new InputStreamReader(s.getInputStream()));
DataOutputStream os =
new DataOutputStream(s.getOutputStream());
// analyse du contenu au bon protocole HTTP
// envoi du document
Android_Clients_Serveur
26
Côté serveur, accept « peut-être »
ServerSocket listen = new ServerSocket(HTTP_PORT);
listen.setSoTimeout(TIME_OUT);
while(!stopped()){
try{
new Connection(listen.accept());
}catch(SocketTimeoutException e){
// ici délai de garde échu
}catch(Exception e){
}
}
listen.close();
}
Par défaut l’appel de accept est bloquant
Méthode accept avec délai de garde
exception SocketTimeoutException à l’échéance
Android_Clients_Serveur
27
Schéma avec Un Pool de Thread
class WebServer { // 2004 JavaOneSM Conference
ThreadPool pool = new ThreadPool(7);
| Session 1358
public static void main(String[] args) {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket s = socket.accept();
Runnable r = new Runnable() {
public void run() {
BufferedReader is = new BufferedReader(
new InputStreamReader(s.getInputStream()));
DataOutputStream os =
new DataOutputStream(s.getOutputStream());
// analyse du contenu au bon protocole HTTP
// envoi du document
}
};
pool.execute(r);
}
}}
Android_Clients_Serveur
28
Côté client
• Usage de telnet
• Requêtes GET et POST en Java
Android_Clients_Serveur
29
Requête GET avec telnet
• Un client telnet et un site du Cnam
– telnet
jfod.cnam.fr
80
• GET /index.html HTTP/1.0 ( frappe sans écho)
HTTP/1.0 200 OK
Last-Modified: Thu, 08 Feb 2007 14:55:29 GMT
Date: Thu, 08 Mar 2007 10:33:55 GMT
Server: Brazil/1.0
Content-Length: 7624
Content-Type: text/html
Connection: close
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
…..
Le résultat est retourné, le source du fichier index.html précédé de quelques informations
Android_Clients_Serveur
30
Requête GET en Java
• L’essentiel
– Créer une URL
– Ouvrir une connexion
• Écrire et lire sur les flots associés
• Classe java.net.URL
• Classe java.net.URLConnection
– URL url = new URL("http://jfod.cnam.fr/index.html" );
– URLConnection connection = url.openConnection();
Android_Clients_Serveur
31
Requête GET au complet
public void testGET()throws Exception{
URL url = new URL("http://jfod.cnam.fr/index.html" );
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine = in.readLine();
while(inputLine != null){
System.out.println(inputLine);
inputLine = in.readLine();
}
in.close();
}
Android_Clients_Serveur
32
Requête GET avec paramètres
public void testGET()throws Exception{
URL url =
new URL("http://jfod.cnam.fr:8999/ds2438/?listAll=on" );
URLConnection connection = url.openConnection();
connection.setDoInput(true);
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine = in.readLine();
while(inputLine != null){
System.out.println(inputLine);
inputLine = in.readLine();
}
in.close();
}
Android_Clients_Serveur
33
Requête POST
URL url = new URL("http://jfod.cnam.fr/index.html");
URLConnection connection = url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.print("listAll=on");
out.close();
BufferedReader in = new BufferedReader( new
InputStreamReader(connection.getInputStream()));
String inputLine = in.readLine();
while(inputLine != null){
System.out.println(inputLine);
inputLine = in.readLine();
}
in.close();
Android_Clients_Serveur
34
Classes utiles
• InetAddress
– Adresse IP en « clair »
• URL
– Pour Uniform Resource Locator, sur le www
• URLConnection
– Une classe abstraite, super classe de toutes les classes établissant un
lien entre une application et une URL
– Sous-classes
• HttpURLConnexion, JarURLConnection
– Patron Fabrique afin d’écrire son propre gestionnaire de protocole
• Voir http://monge.univ-mlv.fr/~roussel/RESEAUJAVA/java.url2.html
• Méthode URLConnection.setContentHandlerFactory( …);
Android_Clients_Serveur
35
En résumé
•
Classe d’accès aux informations
– indépendante du protocole choisi
•
Lecture écriture en 7 étapes
1.
2.
3.
4.
5.
6.
7.
Après avoir créé l’URL.
Obtenir l’instance URLConnection.
Installer les capacités en sortie de cette instance de URLConnection.
Ouvrir le flot en entrée.
Obtenir le flot en sortie.
Écrire sur ce flot.
Fermer celui-ci.
Android_Clients_Serveur
36
Android
• Android
– Toute requête doit être effectuée en dehors de l’UIThread:
– En conséquence, usage de
• AsyncTask
• Service + Thread
Android_Clients_Serveur
37
En « rappel »
Android_Clients_Serveur
le cycle de vie
38
En Rappel: AsyncTask<Params, Progress, Result>
Avec la classe,
AsyncTask<Params, Progress, Result>
– http://developer.android.com/reference/android/os/AsyncTask.html
• Nous avons
– Un thread et l’accès à l’UIThread
• Un thread : pour le traitement en tâche de fond
• Une mise à jour de l’UI incluse
• Les paramètres génériques sont
– Params type des paramètres transmis au Thread
– Progress type des paramètres en cours de traitement transmis au Handler
– Result type du résultat pour l’appelant
Android_Clients_Serveur
39
Résumé: AsyncTask<Params, Progress, Result>
• Depuis l’UIThread
– création d’une instance et appel de la méthode execute
• Exemple new WebAsyncTask().execute(url1, url2, url3);
• AsyncTask<Params, Progress, Result>
– Réalise une encapsulation d’un Thread et de l’accès à l’écran
Méthodes
• onPreExecute()
– Préambule, l’UI exécute cette méthode
• Result doInBackground(Params…p)
– Le contenu de cette méthode s’exécute dans un autre Thread
• onProgressUpdate(Progress…p)
– Mise à jour de l’UI à la suite de l’appel de publishProgress
• onPostExecute(Result)
– Mise à jour de l’UI à la fin de la méthode doInBackground
Android_Clients_Serveur
40
AsyncTask et réseau, exemples
•
Lire une page sur le web HTTP, requête GET
– private class LirePageHTML extends AsyncTask<String,Void,String>{
Schéma
onPreExecute
Afficher une fenêtre d’informations, ProgressDialog
doInBackGround
Ouvrir une connexion, avec un échec éventuel
onPostExecute
Informer l’utilisateur
Android_Clients_Serveur
41
Lire une page Web www.cnam.fr
• Si j’ai la permission … de naviguer sur le web
– <uses-permission android:name="android.permission.INTERNET"></uses-permission>
– Une IHM simple
– L’accès au web est une opération coûteuse alors héritons de AsyncTask
Android_Clients_Serveur
42
Une classe interne héritant de AsyncTask
protected String doInBackground(String... args) {
builder = new StringBuilder();
try {
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(args[0]);
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader =
new BufferedReader( new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} else {error = "Failed to download file";}
} catch (Exception e) {error = e.getMessage();}
return builder.toString();}
Android_Clients_Serveur
43
Autres exemples, essai d’architecture
• 1) Ouverture d’une connexion TCP
– Obtention d’un flux (OutputStream)
– Le flux reste ouvert
• 2) Envois de données sur le flux
– En fonction des opérations de l’utilisateur
• Règle :
l’ouverture de la connexion et l’envoi de données se font sur des threads
• Une solution :
– Ouverture d’une connexion TCP : dans une sous classe d’AsyncTask
– Envoi de données : dans un thread en attente sur une file (SynchronousQueue)
– java.util.concurrent.SynchronousQueue
Android_Clients_Serveur
44
Un schéma d’une architecture possible
UIThread
1) Obtention de la connexion
AsyncTask
Un Thread
2) Envoi de données
offer
take
SynchronousQueue
Réseau
Android_Clients_Serveur
45
Obtention de la connexion, AsyncTask
protected void onPreExecute() {
dialog = ….);
}
protected DataOutputStream doInBackground(String... args) {
boolean result = true;
try{
InetAddress addr = InetAddress.getByName(args[0]);
int port = Integer.parseInt(args[1]);
int timeout = Integer.parseInt(args[2]);
SocketAddress sockaddr = new InetSocketAddress(addr, port);
this.socket = new Socket();
socket.connect(sockaddr, timeout);
out= new DataOutputStream(socket.getOutputStream());
}catch(Exception e){ erreur = e.getMessage();result= false;}
return out;
}
Android_Clients_Serveur
46
Envoi de données depuis l’UIThread
// ici à chaque clic des données sont envoyées vers la file
// les boutons de l’IHM contiennent la commande à envoyer au serveur
public void onClickCommand(View v){
String cmd = v.getContentDescription().toString() + "\n";
try {
sender.offer(cmd.getBytes());
} catch (Exception e) {
}
}
UIThread
Android_Clients_Serveur
offer
47
Envois de données, vers la file
public class Sender extends Thread{
private BlockingQueue<byte[]> queue;
public Sender(){
queue = new SynchronousQueue<byte[]>();
this.start();
}
public boolean offer(byte[] cmd){
return queue.offer(cmd);
}
public void close(){
this.interrupt();
}
public void run(){
while(!isInterrupted()){
try {
byte[] cmd = queue.take(); // lecture bloquante
out.write(cmd);
}catch (Exception e) {
}}
}
Android_Clients_Serveur
48
Sommaire suite
• Bluetooth
• Format XML
Android_Clients_Serveur
49
Bluetooth
• Protocole de communication sans fil
peu chère, peu consommatrice d’énergie…,
adapté aux mobiles
• Spécifications ici http://www.bluetooth.com/bluetooth/
– Bluetooth is not a one-on-one data transmission technology so it can
communicate with up to eight devices within its transmission radius at one time
• Vocable « habituel » :
– Découverte multicast des services
• Client/serveur, serveur/serveur
Android_Clients_Serveur
50
Mesures, à vérifier…
Figures extraites
de http://www.licm.sciences.univ-metz.fr/IMG/pdf/Cours_Bluetooth.pdf
http://www.dandu.be/article/article-bluetooth-comparaison-dongles-46.html
http://www.sena.com/blog/?p=74
BT 2.0 10-100m …
Performances :
Android_Clients_Serveur
à vérifier …
51
Bluetooth, existentiel
• Qui suis-je ?
– Je me présente
• Qui êtes vous ?
– Aux alentours
• Parmi vous qui possède ce service ?
• Avez d’autres services à proposer ?
– Quels sont-ils ?
• UUID ou identification d’un service …
– Adéquation UUID/URL
– UUID prédéfinis, UUID pour une application
• Quels protocoles ?
• Où suis-je, où vais-je ? …
– pas facile voir blipnet ericsson
» http://www.blipsystems.com/files/filer/technical_overview.pdf
Android_Clients_Serveur
52
JSR82 à la rescousse, J2SE
• Deux paquetages
• Qui suis-je ?, qui est là ?, répondez …
– javax.bluetooth.*;
•
•
•
•
Nommage,
Découverte
Recherche de services
Communication
– btspp://localhost:{UUID} + (flux habituels)
– Un protocole répandu OBEX
• java.obex.*;
–
–
–
–
–
btgoep://localhost:localhost:{UUID} + (flux habituels)
tcpobex://1905
Irdaobex://localhost:1900
Session
Transfert d’objets
» put, get
•
•
•
http://java.sun.com/javame/reference/apis/jsr082/javax/bluetooth/package-summary.html
http://www.jsr82.com
http://www.bluecove.org/
Android_Clients_Serveur
53
Qui suis-je ?
• Chaque périphérique BT
possède
• Une adresse (physique) sur 48 bit et unique
– (MAC adresse)
– Un nom lui est associé (en général)
Android_Clients_Serveur
54
Bluetooh et nommage
• 0019EF0117DA
• Devrons nous connaître les adresses physiques ?
–Une UUID associera nom logique / adresse physique
•Universal Unique IDentifier
•http://www.avetana-gmbh.de/avetana-gmbh/produkte/doc/javax/bluetooth/UUID.html
• -> UUID nous utiliserons
Android_Clients_Serveur
55
JSR 82 prémisses
• Initialisation de la pile (protocole)
• A la recherche d’un service
• Découverte de périphériques BT
– Aux alentours
– Nommage/UUID Universally Unique IDentifier (128 bits), existe en version courte
• Communication
– java.io.*, javax.bluetooth.*
– javax.microedition.io.* (inclus dans bluecove)
• Découverte des services
– Au sein de chaque entité
– Nommage/UUID Universally Unique IDentifier (128 bits)
• http://www.handheld-basic.com/documentation/text/page_1766.html
Android_Clients_Serveur
56
Parmi mes voisins …
• Parmi les périphériques BT aux alentours
– Quel est celui qui possède ce service …
• Apparenté à la découverte multicast…
– Un service : un UUID
• new UUID("102030405060708090A0B0C0D0E0F011" ,false)
– 128 bits … pourquoi pas celui-ci …
– Plusieurs BT peuvent répondre pour un service souhaité
• « dépôt d’un fichier », mp3 …
• redondance
Android_Clients_Serveur
57
A la découverte de … obtention d’un agent
import javax.bluetooth.LocalDevice;
import javax.bluetooth.DiscoveryAgent;
public class ALaDécouverteDe{
public static void main(String[] args) throws Exception{
LocalDevice local = LocalDevice.getLocalDevice();
local.setDiscoverable( DiscoveryAgent.GIAC );
// GIAC General inquire Access Code
DiscoveryAgent
agent
= local.getDiscoveryAgent();
un agent capable de tout faire
Sélection d’un service
Effectuer une recherche exhaustive
Android_Clients_Serveur
58
Adéquation UUID / URL
LocalDevice local = LocalDevice.getLocalDevice();
local.setDiscoverable( DiscoveryAgent.GIAC );
// General inquire Access Code
DiscoveryAgent agent = local.getDiscoveryAgent();
UUID uuid = new UUID("102030405060708090A0B0C0D0E0F011", false);
String connString = agent.selectService(uuid,
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
System.out.println("connString : " + connString);
Un exemple d’affichage :
connString: btspp://0019EF01194C:1;authenticate=false;encrypt=false;master=false
0019EF01194C l’adresse physique
:1 le port de communication
Android_Clients_Serveur
59
Un service comme un autre
• Nous avons
– Un service -> un UUID
– un UUID -> une URL
– Une URL -> une communication
• Une syntaxe de type J2ME
– Une communication
• Un flux d’octets, btspp://
• Un flux structuré, btgeop://
Android_Clients_Serveur
60
Exemple de service/UUID
C’est un serveur … protocole btspp://
StreamConnectionNotifier notifier =
(StreamConnectionNotifier)Connector.open(
"btspp://localhost:102030405060708090A0B0C0D0E0F010");
attente d’une requête
StreamConnection conn = notifier.acceptAndOpen();
Android_Clients_Serveur
61
Un serveur au complet
public class SimpleBTSPPServer {
public static void main(String[] args) throws Exception{
LocalDevice local = LocalDevice.getLocalDevice();
local.setDiscoverable(DiscoveryAgent.GIAC);
StreamConnectionNotifier notifier =
UUID
(StreamConnectionNotifier)Connector.open(
"btspp://localhost:" + "102030405060708090A0B0C0D0E0F010");
StreamConnection conn = notifier.acceptAndOpen();
InputStream in = conn.openInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int data;
while ((data = in.read()) != -1) {
out.write(data);
}
System.out.println(" message recu : " + out.toString());
in.close();
conn.close();
notifier.close();
}
}
note : ci-dessus vous avez un
Android_Clients_Serveur
serveur d’une seule connexion… c’est peu…
62
Le client à la recherche de cet UUID
• Les essentiels
• agent .selectService …
String connString = agent.selectService(
new UUID("102030405060708090A0B0C0D0E0F010", false),
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
• StreamConnection
StreamConnection conn = (StreamConnection) Connector.open(connString);
Android_Clients_Serveur
63
Un exemple de client de ce service
public static void main(String[] args) throws Exception{
LocalDevice local = LocalDevice.getLocalDevice();
local.setDiscoverable( DiscoveryAgent.GIAC );
DiscoveryAgent agent = local.getDiscoveryAgent();
String connString = agent.selectService(
new UUID("102030405060708090A0B0C0D0E0F010", false),
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
StreamConnection conn = (StreamConnection) Connector.open(connString);
OutputStream out = conn.openOutputStream();
out.write("next".getBytes());
out.flush();
out.close();
conn.close();
}
}
Android_Clients_Serveur
64
Bluetooth/Android
• Même principe, avec des noms de méthodes différents
– Juste ce qu’il faut pour le TP de télécommande
• Hypothèse le service est en place
– UUID : "10203040-5060-7080-90A0-B0C0D0E0F0FF"
– private UUID MY_UUID = UUID.fromString("10203040-5060-7080-90A0-B0C0D0E0F0FF");
Android_Clients_Serveur
65
Une connexion Bluetooth
• Recherche d’un périphérique bluetooth aux alentours
– Hypothèse : Nous connaissons l’adresse physique du périphérique
• 00:02:72:1A:B4:75 (obtenu ipconfig /all sous windows)
– Cette recherche doit s’effectuer dans un thread
• Alors héritons de AsyncTask
• Au clic
– new ConnexionBT().execute("00:02:72:1A:B4:75");
private class ConnexionBT extends AsyncTask<String,String,BluetoothSocket>{
protected void onPreExecute() {
protected BluetoothSocket doInBackground(String... args) {
protected void onPostExecute(BluetoothSocket btSocket) {
Android_Clients_Serveur
66
onPreExecute : Patience, doInBackground : Recherche
protected void onPreExecute() {
dialog = ProgressDialog.show(BTClientActivity.this,
"connexion Bluetooth", " patientez ", true);
}
protected BluetoothSocket doInBackground(String... args) {
try{
this.btDevice = btAdapter.getRemoteDevice(args[0]);
btSocket =
btDevice.createRfcommSocketToServiceRecord(MY_UUID);
btAdapter.cancelDiscovery();
btSocket.connect();
}catch(Exception e){
erreur = e.getMessage();
btSocket= null;
}
return btSocket;
}
Android_Clients_Serveur
67
Variante sans appairage
protected void onPreExecute() {
dialog = ProgressDialog.show(BTClientActivity.this,
"connexion Bluetooth", " patientez ", true);
}
protected BluetoothSocket doInBackground(String... args) {
try{
this.btDevice = btAdapter.getRemoteDevice(args[0]);
btSocket = btDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
btAdapter.cancelDiscovery();
btSocket.connect();
}catch(Exception e){
erreur = e.getMessage();
btSocket= null;
}
return btSocket;
}
Android_Clients_Serveur
68
onPostExecute(BluetoothSocket btSocket)
protected void onPostExecute(BluetoothSocket btSocket) {
try {
os = btSocket.getOutputStream();
//
} catch (IOException e) {
erreur = e.getMessage();
e.printStackTrace();
}finally{
dialog.dismiss();
}
}
Android_Clients_Serveur
69
Première conclusion
• Serveurs et service
• Client et lecture de flux au format XML et JSON
– XML, SAX
– JSON
Android_Clients_Serveur
70
SAX
SAX Objects
XML Document
<?xml version=“1.0”?>
Parser
startDocument
<addressbook>
Parser
startElement
<name>John Doe</name>
Parser
startElement & characters
<email>[email protected]</email>
Parser
startElement & characters
</person>
Parser
endElement
<person>
Parser
startElement
<name>Jane Doe</name>
Parser
startElement & characters
<email>[email protected]</email>
Parser
startElement & characters
Parser
endElement
Parser
endElement & endDocument
<person>
</person>
</addressbook>
Android_Clients_Serveur
71
Implémenter les Handlers d'évènements du parseur
DefaultHandler
Il implémente ces
différents Handler
avec des méthodes
vides, de sorte que l'on
peut surcharger
seulement celles qui
nous intéressent.
Android_Clients_Serveur
72
org.xml.sax.ContentHandler
Toutes
les applications SAX doivent implanter un ContentHandler
Méthodes
:
–public
void startDocument() throws SAXException
–public
void endDocument() throws SAXException
–public
void startElement(String nspURI, String localName, String qName,
Attributes atts) throws SAXException
–public
void characters(char[] ch, int start, int length) throws SAXException
–…
Android_Clients_Serveur
73
Un exemple: les stations Vélib
– http://www.velib.paris.fr
– http://www.velib.paris.fr/service/carto
– http://www.velib.paris.fr/service/stationdetails/{number}
Android_Clients_Serveur
74
http://www.velib.paris.fr/service/carto
<carto>
<markers>
<marker name="00901 - STATION MOBILE 1" number="901"
address="ALLEE DU BELVEDERE PARIS 19 - 0 75000 Paris -"
fullAddress="ALLEE DU BELVEDERE PARIS 19 - 0 75000 Paris 75000 PARIS" lat="48.892745582406675"
lng="2.391255159886939" open="1" bonus="0"/>
<marker name="03011 - TURBIGO" number="3011" address="55 RUE
TURBIGO -" fullAddress="55 RUE TURBIGO - 75003
PARIS" lat="48.86558781525867"lng="2.356094545731025" open
="1" bonus="0"/>
Analyse des attributs
de la balise marker
en SAX -> méthode startElement
Android_Clients_Serveur
75
http://www.velib.paris.fr/service/stationdetails/3011
<station>
<available>21</available>
<free>10</free>
<total>31</total>
<ticket>1</ticket>
</station>
Analyse du contenu
de la balise station
en SAX -> des méthodes startElement, endElement, characters
Android_Clients_Serveur
76
Les stations Vélib: suite
• Les Classes, un premier découpage
– StationVelib,
• toutes les infos d’une station, (adresse, longitude, latitude,…)
– InfoStation,
• les informations comme le nombre de vélo et d’emplacements disponibles,...
– ListeDesStationsVelib
• La gestion de la liste des stations
– http://www.velib.paris.fr/service/carto
– http://www.velib.paris.fr/service/stationdetails/{number}
Android_Clients_Serveur
77
Initialisation du « parser »
class ParserXML
extends DefaultHandler {
public ParserXML(InputStream in)
throws Exception{
SAXParserFactory spf =
SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setContentHandler(this);
xr.parse(new InputSource(in));
}
Android_Clients_Serveur
78
startElement un extrait
// Création d’une instance de la classe StationVelib
// depuis XML en Java
public void startElement(String uri, String localName, String qName,Attributes
attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if(qName.equals("marker")){
StationVelib station = new StationVelib();
station.setName(attributes.getValue("name"));
station.setNumber(Integer.parseInt(attributes.getValue("number")));
station.setAddress(attributes.getValue("address"));
station.setLatitude(Double.parseDouble(attributes.getValue("lat")));
station.setLongitude(Double.parseDouble(attributes.getValue("lng")));
}
Android_Clients_Serveur
79
Une Info à chaque Station
class ParserXML extends DefaultHandler {
private StringBuffer current; // la valeur
public ParserXML(int ID){
URL url = new URL(URL_VELIB_INFO + ID);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp;
sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setContentHandler(this);
xr.parse(new InputSource(url.openStream()));
}
Android_Clients_Serveur
80
A chaque noeud
public void startElement (String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
current = new StringBuffer();
}
public void characters (char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
current.append(new String(ch, start, length));
}
public void endElement (String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if(qName.equals("available")){
available = Integer.parseInt(current.toString());
…
}
Android_Clients_Serveur
81
XML plutôt verbeux, JSON plutôt concis
• JSON JavaScript Object Notation
– www.json.org/
– JSONArray
– JSONObject
JSONArray jsonArray = new JSONArray();
JSONObject jsonObject = new JSONObject();
jsonObject.put( "name", "paul");
jsonObject.put("number", 1900);
jsonArray.put(jsonObject);
// pierre idem
System.out.println(jsonArray.toString(2));
Android_Clients_Serveur
82
JSON, exemple paul et pierre
• [
• {
•
"name": "paul",
•
"number": 1900
• },
• {
•
"name": "pierre",
•
"number": 1900
• }
• ]
Android_Clients_Serveur
83
JSON Lecture
InputStream in = …;
Reader r = new InputStreamReader(in);
BufferedReader br = new BufferedReader(r);
StringBuffer sb = new StringBuffer();
String str;
while((str = br.readLine()) != null) {
sb.append(str);
}
r.close();
JSONArray jsonarray = new JSONArray(sb.toString());
JSONObject jsonObject = (JSONObject)jsonStations.get(i);
Auditeur a = new Auditeur ();
a.setName(jsonObject.getString("name"));
…
Android_Clients_Serveur
84
StationVelib, lecture JSON
JSONArray jsonStations = new JSONArray(sb.toString());
for(int i=0; i< jsonStations.length(); i++){
JSONObject jsonObject = (JSONObject)jsonStations.get(i);
StationVelib st = new StationVelib();
st.setName(jsonObject.getString("name"));
st.setNumber(jsonObject.getInt("number"));
st.setAddress(jsonObject.getString("address"));
st.setFullAddress(jsonObject.getString("fullAddress"));
st.setLatitude(jsonObject.getDouble("lat"));
st.setLongitude(jsonObject.getDouble("lng"));
st.setOpen(jsonObject.getBoolean("open"));
st.setBonus(jsonObject.getBoolean("bonus"));
Android_Clients_Serveur
85
Démonstration
Android_Clients_Serveur
86
Conclusion
• Discussions
Android_Clients_Serveur
87
Téléchargement