<div class="page"> <div class="cover text-center"> <img class="mx-auto" src=/itb/images/logo_mislata.png alt="logo"> # Protocols de comunicació <div class="text-end fit-content ms-auto my-3 mt-auto pt-3"> <p><strong>Autor:</strong> Joan Puigcerver Ibáñez</p> <p><strong>Correu electrònic:</strong> j.puigcerveribanez@edu.gva.es</p> <p><strong>Curs:</strong> 2024/2025</p> </div> <div> <p class="fw-bold mb-0">Llicència: BY-NC-SA</p> <p class="d-none d-md-block">(Reconeixement - No Comercial - Compartir Igual)</p> <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ca" target="_blank"> <img class="mx-auto" src="/itb/images/license.png" alt="Licence"/> </a> </div><!--license--> </div><!--cover--> </div><!--page--> {:toc} ## Introducció Un __protocol de comunicació__ és un conjunt de regles que defineix com s'intercanvia la informació entre diversos dispositius o aplicacions. Aquestes regles determinen la forma en què les dades s'estructuren per al seu enviament i recepció. Normalment, cal tindre en compte els següents aspectes a l'hora de treballar amb un protocol o dissenyar-ne un: 1. __Tipus de missatge__: - Decideix quins tipus de missatges seran necessaris per a la teua aplicació (peticions, respostes, notificacions, etc.). - Assigna identificadors únics (codis o noms) a cada tipus de missatge. 2. __Estructura del missatge__: Defineix l'estructura de les dades per al seu enviament i recepció. Es poden utilitzar els següents formats: - __Objectes Serialitzats__: Objectes del llenguatge programació traduits a binari (`bytes`). - __Llenguatges de marques estructurats__: Es poden utilitzar llenguatges de marques per estructurar la informació. Els formats més comuns i utilitzats en comunicació són __JSON__ i __XML__. 3. __Autenticació i Autorització__: - Defineix com es gestionarà l'autenticació dels clients. - Estableix mecanismes per gestionar permisos sobre quins clients tenen accés a quina informació. 4. __Gestió d'errors__: - Defineix com es gestionaran els possibles errors durant la comunicació. - Pots utilitzar codis per indicar l'estat de cada missatge. 5. __Seqüencia__: - Estableix una seqüència lògica per a les interaccions entre el client i el servidor. - Determina l'ordre en què es poden enviar i rebre els diferents tipus de missatges. Una vegada dissenyat el protocol cal proporcionar una __documentació detallada__ i completa que explique totes les possibles interaccions, la informació que es transmet i com s'ha de processar. ## Exemple: Protocol HTTP El __protocol de transferència d'hipertext__ o __HTTP__ (_HyperText Transfer Protocol_) estableix el protocol per a l'intercanvi de documents d'hipertext i multimèdia al web. HTTP disposa d'una variant xifrada mitjançant SSL anomenada HTTPS. És el protocol utilitzat per la visualització de pàgines web. ::: docs - Especificació del protocol: https://www.w3.org/Protocols/Specs.html ::: Aquest protocol té una estructura __client-servidor__. El protocol HTTP té diferents tipus de peticions. Els més comuns són: - `GET`: Sol·licita dades d'un recurs. - `POST`: Envia dades al servidor per processar-les. - `PUT`: Actualitza les dades d'un recurs o crea un nou recurs si no existeix. - `DELETE`: Elimina un recurs específic. ::: docs - Llista dels tipus de peticions completa: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods ::: A més, HTTP utilitza una sèrie de codis per indicar si la petició efectuada s'ha pogut portar a terme i aixi, poder gestionar els errors correctament. Alguns dels codis més comuns són: - `200`: La sol·licitud ha tingut èxit. - `400`: La sol·licitud no s'ha pogut processar perquè el servidor no ha entés la petició, segurament per algun error del client. - `404`: Indica que la sol·licitud és vàlida però que el recurs sol·licitat no existeix. - `500`: Indica que el servidor ha tingut algun error mentre processava la petició del client. - `503`: Indica que el client no té permitit l'accés al recurs sol·licitat. ::: docs - Llista dels codis de reposta completa: https://developer.mozilla.org/es/docs/Web/HTTP/Status ::: ## Java: Enviament d'objectes Una de les maneres de poder enviar informació estructurada és mitjançant __objectes serialitzats__, és a dir, objectes del llenguatge de programació que han segut convertits a bytes. Aquesta opció té l'avantatge que és molt còmoda, ja que pots enviar i rebre objectes directament sense la necessitat de processar el missatge. No obstant això, té l'inconvenient que la estructura dels objectes i la serialització depén del llenguatge de programació, per tant, és poc versàtil en el sentit que cal utilitzar el mateix llenguatge de programació per als clients i servidors. ### Interfície `Serializable` Abans que res, cal implementar l'interfície `Serializable` en tots els objectes que s'utilitzaran en la comunicació. Simplement cal implementar la interfície i no cal realitzar cap acció addicional en aquest pas. Amb això, Java ja sap com convertir l'objecte a binari. ::: docs - Interfície `Serializable`: https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html ::: ::: example - Objecte `Request` que implementa una petició o comunicació entre el servidor i el client. - Objecte `RequestType` que implementa els diferents tipus de peticions que hi haurà. Com que l'objecte `Request` conté un objecte `RequestType`, també cal serialitzar-lo. __Request.java__ ```java package ud3.examples.cinema.models; import java.io.Serializable; /** * Classe que representa una petició o resposta entre el servidor i el client. * <p> * Aquesta classe implementa Serialitzable per poder ser convertida a * bytes i poder ser enviada mitjançant sockets. */ public class Request implements Serializable { /** * Tipus de petició (GET/POST/SUCCESS/ERROR) * @see RequestType */ private RequestType type; /** * Objecte que es pot adjuntar a la comunicació */ private Object object; /** * Missatge opcional que es pot adjuntar a la comunicació */ private String message; /** * Constructor de la petició * @param type Tipus de la petició * @param object Objecte adjuntat */ public Request(RequestType type, Object object) { this.type = type; this.object = object; } /** * Constructor de la petició * @param type Tipus de la petició * @param object Objecte adjuntat * @param message Missatge adjuntat */ public Request(RequestType type, Object object, String message) { this.type = type; this.object = object; this.message = message; } public RequestType getType() { return type; } public void setType(RequestType type) { this.type = type; } public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } ``` __RequestType.java__ ```java package ud3.examples.cinema.models; import java.io.Serializable; /** * Enumeració amb els diferents tipus de peticions que podem trobar * <p> * Aquesta classe implementa Serialitzable per poder ser convertida a * bytes i poder ser enviada mitjançant sockets. */ public enum RequestType implements Serializable { /** * El tipus GET s'utilitza per sol·licitar algun element del servidor */ GET, /** * El tipus POST s'utilitza per enviar algun element al servidor */ POST, /** * El tipus SUCCESS s'utilitza per indicar que l'acció s'ha dut a terme correctament */ SUCCESS, /** * El tipus SUCCESS s'utilitza per indicar que l'acció no s'ha dut a terme correctament */ ERROR } ``` ::: ### Enviament i recepció d'objectes L'enviament i recepció d'objectes es gestionen amb les classes `ObjectOutputStream` i `ObjectInputStream`, que s'inicialitzaran amb el `OutputStream` o `InputStream` del `Socket` corresponent. ::: docs - Classe `ObjectOutputStream`: https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html - Classe `ObjectInputStream`: https://docs.oracle.com/javase/8/docs/api/java/io/ObjectInputStream.html ::: - __Enviament__: ```java ObjectOutputStream objOut = new ObjectOutputStream(socket.getOutputSteam()); Request req = new Request(RequestType.POST, new Film("La vida es bella", 1997, 116)) objOut.writeObject(request); ``` - __Recepció__: En la recepció cal fer un 'casting' per poder obtindre l'objecte com al seu tipus corresponent, ja que el mètode `readObject()` retorna un `Object`. ```java ObjectInputStream objin = new ObjectInputStream(socket.getInputStream()); Request req = (Request) objIn.readObject(); if(req.getType() == RequestType.POST) Film film = (Film) req.getObject(); ``` ## Bibliografia - https://ca.wikipedia.org/wiki/Protocol_de_comunicaci%C3%B3 - https://ca.wikipedia.org/wiki/Protocol_de_transfer%C3%A8ncia_d%27hipertext - https://www.w3.org/Protocols/Specs.html