Saltar a contenido

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.

Los fuentes en github

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>
Incluye variso ejemplos

16. Construir un chat usando webosocket y Servlets

aqui

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 o Decoder.Binary interfaces.

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 
Siempre que se envia o recibe se aplica la transformación JSON <-> Objeto java