Tuesday, 2 May 2017

WebSocket


WebSocket is an application protocol that provides full-duplex communications between two peers over the TCP protocol.
In a WebSocket application, the server publishes a WebSocket endpoint, and the client uses the endpoint's URI to connect to the server. The WebSocket protocol is symmetrical after the connection has been established; the client and the server can send messages to each other at any time while the connection is open, and they can close the connection at any time. Clients usually connect only to one server, and servers accept connections from multiple clients.

The WebSocket protocol has two parts: handshake and data transfer. The client initiates the handshake by sending a request to a WebSocket endpoint using its URI. The handshake is compatible with existing HTTP-based infrastructure: web servers interpret it as an HTTP connection upgrade request.

The server applies a known operation to the value of the Sec-WebSocket-Key header to generate the value of the Sec-WebSocket-Accept header. The client applies the same operation to the value of the Sec-WebSocket-Key header, and the connection is established successfully if the result matches the value received from the server. The client and the server can send messages to each other after a successful handshake.

WebSocket endpoints are represented by URIs that have the following form:

ws://host:port/path?query
wss://host:port/path?query

The ws scheme represents an unencrypted WebSocket connection, and the wss scheme represents an encrypted connection. The port component is optional; the default port number is 80 for unencrypted connections and 443 for encrypted connections. The path component indicates the location of an endpoint within a server. The query component is optional.



Example : -
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class WebSocketClientHandler extends TextWebSocketHandler{

     @Override
     public void afterConnectionEstablished(WebSocketSession session) throws Exception {
            System.out.println("Inside client afterConnectionEstablished :: sessionId :: " + session.getId());
            session.sendMessage(new TextMessage("Sending message to server..."));
     }

     @Override
     public void handleTextMessage(WebSocketSession session, TextMessage message)
                throws Exception {
           System.out.println("Client Recieved Message :: "+message.toString());
     }

     @Override
     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
           System.out.println("Exception occured :: " + session.getId());
     }

     @Override
     public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
           System.out.println("Client connection closed for sessionId :: " + session.getId());
     }

     @Override
     public boolean supportsPartialMessages() {
           return true;
     }
Server Handler :
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.google.gson.Gson;

@Component
public class WebSocketServerHandler extends TextWebSocketHandler {

     private static Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);

     List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();

     @Override
     public void afterConnectionEstablished(WebSocketSession session) {
           logger.info("Inside server afterConnectionEstablished:: sessionId:: " + session.getId());
     }

     @SuppressWarnings("rawtypes")
     @Override
     public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
           String echoMessage = message.getPayload();
           logger.info(echoMessage);
           for(WebSocketSession webSocketSession : sessions) {
                Map value = new Gson().fromJson(message.getPayload(), Map.class);
                webSocketSession.sendMessage(new TextMessage("Hello " + value.get("name") + " !"));
           }
     }

     @Override
     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
           session.close(CloseStatus.SERVER_ERROR);
     }
    
     @Override
     public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
           System.out.println("Inside Server afterConnectionClosed for sessionId :: " + session.getId());
     }
}