Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parMainard Gallais Modifié depuis plus de 10 années
1
Connectivité, Web Services Orienté clients/serveur TCP et Bluetooth
jean-michel Douin, douin au cnam point fr version : 26 Mars 2013 Notes de cours Avertissement :
2
Bibliographie utilisée
Un ensemble de tutoriels à lire
3
Clients et serveurs TCP
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
4
Client et serveur Serveurs TCP Exemples Requête
5
Serveurs En mode TCP Appels distants en mode TCP/IP
Point à point avec accusé de réception telnet, ftp, http, …
6
URL … URL Uniform Resource Locator une adresse sur internet
http le protocole //jfod.cnam.fr le nom de la ressource
7
Exemples clients / serveurs
protocole Client1 Client2 Client3 Serveur Le client s’adresse au serveur Établit une connexion Le serveur satisfait ses clients Mode synchrone, analogue à l’appel d’une méthode locale
8
Appels distants protocole « maison »
Client1 Client2 Client3 serveur JVM JVM Le contexte Client Java, ou autres Serveur en java ou autre maison : //serveur/….
9
Appels distants protocole http
Client1 Client2 un navigateur serveur JVM JVM Le contexte Client Java(application comme applette), ou autres Un navigateur Serveur en java , ou autres http: //serveur/index.html Standard, universel …
10
Implémentation en Java
Paquetage java.net Principales classes ServerSocket Socket InetAddress URLConnection … Quelques lignes de sources suffisent …
11
usage de java.net TCP/IP
Client1 Serveur JVM JVM 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
12
Connexion / Principes Serveur Client1 port
JVM JVM port port 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)
13
2 exemples Serveur et client Au protocole « maison » Au protocole http
Le serveur ne connaît que la commande « parle » et répond « bonjour » Tout autre commande est ignorée ! Au protocole http Seule la méthode GET /index.html HTTP1.0 est possible Un sous-ensemble donc …
14
Exemple 1 maison: //serveur parle Client1 Serveur bonjour
JVM JVM 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
15
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();
16
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(); }
17
Un client « maison », telnet
telnet localhost 5000 parle // frappe sans écho petit outil utile : tcpview
18
Exemple 2 Le protocole HTTP Mise en œuvre / démo
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
19
Protocole HTTP HyperText Transfer Protocol Les Méthodes
Au dessus de TCP Les Méthodes GET /index.html HTTP/1.0 HEAD POST PUT DELETE TRACE CONNECT Voir
20
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.
21
Exemple minimaliste ! Un serveur Web au complet Extrait de
Un seul client, une seule requête ! Extrait de
22
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()); }}
23
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");
24
OneShotHttpd.main(s);
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){ } 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 OneShotHttpd.main(s);
25
Côté serveur, un thread à chaque requête
ServerSocket listen = new ServerSocket(HTTP_PORT); while(!stopped()){ try{ new Connection(listen.accept()); // création d’une instance }catch(Exception e){ } 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 »
26
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
27
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
28
Schéma avec Un Pool de Thread
class WebServer { // 2004 JavaOneSM Conference | Session 1358 ThreadPool pool = new ThreadPool(7); 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); }}
29
Côté client Usage de telnet Requêtes GET et POST en Java
30
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/ OK Last-Modified: Thu, 08 Feb :55:29 GMT Date: Thu, 08 Mar :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 "> ….. Le résultat est retourné, le source du fichier index.html précédé de quelques informations
31
Requête GET en Java L’essentiel Classe java.net.URL
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(" ); URLConnection connection = url.openConnection();
32
Requête GET au complet public void testGET()throws Exception{
URL url = new URL(" ); 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();
33
Requête GET avec paramètres
public void testGET()throws Exception{ URL url = new URL(" ); 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();
34
Requête POST connection.setDoOutput(true);
URL url = new URL(" 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();
35
Classes utiles InetAddress URL URLConnection Adresse IP en « clair »
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 Méthode URLConnection.setContentHandlerFactory( …);
36
En résumé Classe d’accès aux informations Lecture écriture en 7 étapes
indépendante du protocole choisi Lecture écriture en 7 étapes 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.
37
Android Android Toute requête doit être effectuée en dehors de l’UIThread: En conséquence, usage de AsyncTask Service + Thread
38
En « rappel » le cycle de vie
39
En Rappel: AsyncTask<Params, Progress, Result>
Avec la classe, AsyncTask<Params, Progress, Result> 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
40
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
41
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
42
Lire une page Web 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
43
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();}
44
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
45
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
46
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;
47
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 offer
48
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) { }}
49
Une connexion Bluetooth
Recherche d’un périphérique bluetooth aux alentours Hypothèse : Nous connaissons l’adresse physique du périphérique 00-19-EF C (obtenu ipconfig /all sous windows) Cette recherche doit s’effectuer dans un thread Alors héritons de AsyncTask Au clic new ConnexionBT().execute("00:19:EF:01:17:9C"); private class ConnexionBT extends AsyncTask<String,String,BluetoothSocket>{ protected void onPreExecute() { protected BluetoothSocket doInBackground(String... args) { protected void onPostExecute(BluetoothSocket btSocket) {
50
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;
51
onPostExecute(BluetoothSocket btSocket)
protected void onPostExecute(BluetoothSocket btSocket) { try { os = btSocket.getOutputStream(); // } catch (IOException e) { erreur = e.getMessage(); e.printStackTrace(); }finally{ dialog.dismiss(); }
52
Première conclusion Serveurs et service
Client et lecture de flux au format XML et JSON XML, SAX rappels cf. supports NFP121 JSON
53
SAX XML Document SAX Objects Parser startDocument Parser startElement
<?xml version=“1.0”?> Parser startDocument <addressbook> </addressbook> Parser startElement <person> </person> <name>John Doe</name> Parser startElement & characters Parser startElement & characters Parser endElement <person> </person> Parser startElement <name>Jane Doe</name> Parser startElement & characters Parser startElement & characters Parser endElement Parser endElement & endDocument
54
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.
55
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 …
56
Un exemple: les stations Vélib
57
http://www.velib.paris.fr/service/carto <carto> <markers>
<marker name=" STATION MOBILE 1" number="901" address="ALLEE DU BELVEDERE PARIS Paris -" fullAddress="ALLEE DU BELVEDERE PARIS Paris PARIS" lat=" " lng=" " open="1" bonus="0"/> <marker name=" TURBIGO" number="3011" address="55 RUE TURBIGO -" fullAddress="55 RUE TURBIGO PARIS" lat=" "lng=" " open="1" bonus="0"/> Analyse des attributs de la balise marker en SAX -> méthode startElement
58
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
59
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
60
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)); }
61
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"))); }
62
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())); }
63
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()); …
64
XML plutôt verbeux, JSON plutôt concis
JSON JavaScript Object Notation 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));
65
JSON, exemple paul et pierre
[ { "name": "paul", "number": 1900 }, "name": "pierre", } ]
66
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")); …
67
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"));
68
Démonstration
69
Conclusion Discussions
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.