14. WEBSOCKET¶
Como nos dice la wikipedia un websocket es un canal de comunicación bidireccional fullduples usando un único sockey tcp.
Esquema de URL La especificación del protocolo WebSocket define dos nuevos esquemas de URI, ws: y wss:,6 para conexiones no cifradas y cifradas respectivamente. Además del nombre del esquema, el resto de componentes del URI se definen con la sintaxis genérica de URI.7
El canal de websocket queda abierto permitiendo que tanto el servidor como el cliente inicien la transmisión.
los WebSockets vienen como estandar a partir de Java EE 7 en la especificación JSR 356.
En esta web de MDN hay ejemplo de cliente servidor y una lista de herramientas.
15. Websocket simple Java-websocket¶
Uso simple adaptado en github
Usando maven, incluir:
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.3</version>
</dependency>
16. Construir un chat usando webosocket y Servlets¶
16.1 Servidor¶
Para funcionar se necesita además un servidor como TOMCAT.
Añadimos dependecias en pom.xml
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
Para la codificación y decodificación usamos GSON
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
16.1.1 Configuración de los "endpoint"¶
Se puede hacer de dos formas: extendiendo la clase javax.websocket.Endpoint o bien mediante anotaciones en los métodos.
Por claridad se prefieren las anotaciones.
* @ServerEndpoint: con este decorador el contenedor nos garantiza que la clase será un servidor websocket escuchando a un URI concreta.
* @ClientEndpoint: La clase con este decorador es un cliente websocket
* @OnOpen: El método con este decorador, es invocado por el contenedor cuando se establece una nueva conexión.
* @OnMessage: El método con este decorador recibe la información de un contenedor de websocket cuando se envia un mensaje al endpoint.
* @OnError:
* @OnClose:
16.1.2 Código del cliente.¶
La URI es relativa y siempre debe comentar por /
@ServerEndpoint(value="/chat/{username}")
public class ChatEndpoint {
private Session session;
private static Set<ChatEndpoint> chatEndpoints
= new CopyOnWriteArraySet<>();
private static HashMap<String, String> users = new HashMap<>();
@OnOpen
public void onOpen(
Session session,
@PathParam("username") String username) throws IOException {
this.session = session;
chatEndpoints.add(this);
users.put(session.getId(), username);
Message message = new Message();
message.setFrom(username);
message.setContent("Connected!");
broadcast(message);
}
@OnMessage
public void onMessage(Session session, Message message)
throws IOException {
message.setFrom(users.get(session.getId()));
broadcast(message);
}
@OnClose
public void onClose(Session session) throws IOException {
chatEndpoints.remove(this);
Message message = new Message();
message.setFrom(users.get(session.getId()));
message.setContent("Disconnected!");
broadcast(message);
}
@OnError
public void onError(Session session, Throwable throwable) {
// Do error handling here
}
private static void broadcast(Message message)
throws IOException, EncodeException {
chatEndpoints.forEach(endpoint -> {
synchronized (endpoint) {
try {
endpoint.session.getBasicRemote().
sendObject(message);
} catch (IOException | EncodeException e) {
e.printStackTrace();
}
}
});
}
}
16.2 Tipos de mensajes¶
Pueden ser binarios o texto.
* Texto: cualquier valor de texto (java.lang.String)
* Binario: audio, imagenes, etc
* Objetos Java. Se pueden usar objetos nativos java realizando encoder/decoder como especifica el API.
* Ping-Pong: Un mensaje javax.websocket.PongMessage indica el "acknowledgment" enviado por el otro exteremo en el websocket (todo ok)
16.2.1 Encoder¶
Toma un objeto y lo trasforma en JSON, XML u otro formato para transmitir.
Por ejemplo. Con la clase Message
public class Message {
private String from;
private String to;
private String content;
//standard constructors, getters, setters
}
public class MessageEncoder implements Encoder.Text<Message> {
private static Gson gson = new Gson();
@Override
public String encode(Message message) throws EncodeException {
return gson.toJson(message);
}
@Override
public void init(EndpointConfig endpointConfig) {
// Custom initialization logic
}
@Override
public void destroy() {
// Close resources
}
}
16.2.2 Decoder¶
Decoders pueden implementarse usando Decoder.Text
public class MessageDecoder implements Decoder.Text<Message> {
private static Gson gson = new Gson();
@Override
public Message decode(String s) throws DecodeException {
return gson.fromJson(s, Message.class);
}
@Override
public boolean willDecode(String s) {
return (s != null);
}
@Override
public void init(EndpointConfig endpointConfig) {
// Custom initialization logic
}
@Override
public void destroy() {
// Close resources
}
}
16.2.3 Establecer Encoder y Decoder en el "endpoit" del Server¶
Se añade las siguientes líneas:
@ServerEndpoint(
value="/chat/{username}",
decoders = MessageDecoder.class,
encoders = MessageEncoder.class