<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