What is Websocket? How Websocket works? Program on updating total count of connected Clients.

What is Websocket?


Websocket is bi-directional communication protocol over web that helps client to server and server to client communication on single TCP connection and on same port.

What is the use of Websocket and how it is helpful?
How things works before Websocket ?


For communication on web, HTTP is the standard protocol that is used.


HTTP is stateless protocol. It means,
    1. Client Request connection
    2. Connection established
    3. Client sends a request.
    4. Server gives response.
    5. Connection closed

Now client and server are independent and unaware of each other.
If client want to communicate again then it has to again go with above steps,
Also, request is always initiated by client and server can't initiate communication.


So, if Server has to say something to the client then how to achieve that?


First of all, why server want to communicate with the client, Lets see below example,
   1. Say, Jayesh requested for fare information of Flight number MH 198 from Mumbai 
       to Ahmedabad. 
   2. Server responded to Jayesh "Price is 5000 INR."
   3. Jayesh is thinking whether to book a flight at 5000 INR and then finally after 5 minutes,
        he made a mind to book it.
   4. Now after filling long form of passenger list and other flight information, 
       when Jayesh pressed the "Book" button, he found that now Flight price is 6000 INR, 
       how this happen??????????
   5. Jayesh is frustrated and thinking why server not notified him before filling the long form 
       on passenger list.

Ideally, Server should notify Jayesh that flight price is changed, please refresh the page. 
But how the server will know that to which all clients he need to inform and top of all, Server doesn't know any information on client.
This is possible only if server is capable of identifying client that, "who all client are connected to server and notify them on updates".

As communication happens over HTTP, Before Websocket, Server notify to the client using below techniques,

1. Polling


In this technique,
  1. Client requests a webpage from a server using regular HTTP request.
  2. The requested webpage executes JavaScript which requests for updates from the server at 
       regular intervals (say 1 seconds).
  3. The server checks for updates and responds back, just like normal HTTP response.

In Polling, client continuously polls server at regular intervals, asking is there any updates for client?

Disadvantage: if there is no updates, then unnecessarily client sends request to server and it hits server performance.

2. Long Polling


In this technique, 
  1. A client requests a webpage from a server using regular HTTP request.
  2. The requested webpage executes JavaScript which requests for updates from the server.
  3. Now if server does not has any updates, then server does not immediately responds telling 
      "no update" instead waits until there's new information available.
      When there's update available, the server responds with the updated information that help 
      client  on information say price has changed.
  4. The client receives updated price information and immediately sends another request 
       to the server, re-starting the process.

Disadvantage: Server like Tomcat would spawned thread to handle for each request, that reserve resources, till its done. So the traffic is smaller, but eats resources fast (also block resources).

Websocket overcome issues present in Polling and Long Polling.
One limitation with Websocket is that it is only supported with HTML 5 compliant  browsers.

Lets see a sample application on updating total count of connected clients using WebSockets, AngularJS and Java.


Client Side HTML and Javascript

index.html
<!DOCTYPE html>
<html>
 <head>
 
  <title>Websocket Example</title>  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.0/angular.js"></script>
  <script src="app.js"></script>  
 
 </head>
 <body  data-ng-app="websocketDemoApp" style="margin:0px;">  
  
  <div data-ng-controller="appController">
   
   <label style="font-size: 20px; font-weight: bold;">Messages from Websocket Communication : </label>
   <pre>{{ websocketMessage }}</pre><br>
   
   <label style="font-size: 20px; font-weight: bold;">Connected Clients : </label>
   <label style="font-size: 40px; font-weight: bold;">{{ numberOfUsersConnected }}</label>
   
  </div>
  
 </body>
</html> 
app.js
'use strict';
var module = angular.module('websocketDemoApp', [ ]);

angular.module('websocketDemoApp').controller("appController", ['$scope', function($scope) {

 $scope.websocketMessage = "";
 
 $scope.getURLWithOutProtocalFromCurrentContext = function() {
  var hostName = window.location.host;
  var currentPath = window.location.pathname;
  return hostName + currentPath;
 };
 
 var urlWithOutProtocol = $scope.getURLWithOutProtocalFromCurrentContext();
 var wsUri = "ws://" + urlWithOutProtocol +"endpoint";
 var websocket = new WebSocket(wsUri);
 
 websocket.onopen = function(evt) {
  console.log("connection established");
  
  $scope.$apply(function(){
   $scope.websocketMessage = $scope.websocketMessage + "Connection to Websocket has established." + "\n";
        });
  
 };
 
 websocket.onmessage = function(evt) {
  console.log("message received: "+evt.data);
  var jsonResponse = JSON.parse(evt.data);
  
  $scope.$apply(function(){
   
   if(jsonResponse.count!=null || !angular.isUndefined(jsonResponse.count))
    $scope.numberOfUsersConnected = jsonResponse.count;
   
   if(jsonResponse.message!=null || !angular.isUndefined(jsonResponse.message))
    $scope.websocketMessage = $scope.websocketMessage + "Data Received: " +jsonResponse.message + "\n";
   
   
  });
 };
 
 websocket.onerror = function(evt) {
  console.log('websocket error: ' + jsonResponse);
  $scope.websocketMessage = $scope.websocketMessage + "There is some error while establishing connection to web socket." + "\n";
 };
 
 websocket.onclose = function(){
  $scope.websocketMessage = $scope.websocketMessage + "Web Socket connection is closed now..." + "\n";
    };
 
}]);


Server Side Java Code

ServerPush.java
package com.websocket.test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/endpoint")
public class ServerPush {
 private static Map<Object, Session> mapConnections = new HashMap<Object, Session>();

 public ServerPush() {
  //Starting notifier to push data to client at 1 minute interval
  new NotifierExample();
 }

 //This method is called when websocket connection is established or open.
 @OnOpen
 public void start(Session session) {
  mapConnections.put(session.getId(), session);
  String json = "{ \"count\" : \""+mapConnections.size()+"\"}"; 
  broadcastToAll(json);
 }

 @OnMessage
 public void echoTextMessage(Session session, String msg, boolean last) {
  String json = "{ \"count\" : \""+mapConnections.size()+"\"}";
  broadcastToAll(json);
 }
 
 //This method is called when websocket connection is closed or when browser tab is closed. 
 @OnClose
 public void end(Session session, CloseReason reason) {
  mapConnections.remove(session.getId());
  String json = "{ \"count\" : \""+mapConnections.size()+"\"}"; 
  broadcastToAll(json);
 }

 //For sending data to single connected client for one to one communication between client and server.
 public static void broadcast(String key, String message) {
  Session session = mapConnections.get(key);
  if(session!=null){
   try {
    session.getBasicRemote().sendText(message);
   } catch (IOException e) {
    try {
     session.close();
    } catch (IOException e1) {
     // Ignore
    }
   }
  }
 }

 //For sending data to all the connected clients
 public static void broadcastToAll(String message) {
  for(Session session : mapConnections.values()){
   if(session!=null){
    try {
     session.getBasicRemote().sendText(message);
    } catch (IOException e) {
     try {
      session.close();
     } catch (IOException e1) {
      // Ignore
     }
    }
   }
  }
 }

}

NotifierExample.java
package com.websocket.test;

import java.util.Timer;
import java.util.TimerTask;

public class NotifierExample extends TimerTask{

 //After every 60 seconds, server will push the data to all connected clients.
 public NotifierExample() {
     Timer timer = new Timer();
     timer.schedule(this, 5000, 60000);
 }
 
 @Override
 public void run() {
  String json = "{ \"message\" : \"Database table is updated, Please refresh to get updated records.\"}";
  ServerPush.broadcastToAll(json);
 }
}


Note: ServerPush.java use classes from websocket jar, So make sure you have websocker-api.jar present in tomcat lib folder, if not then download using below dependency,

    javax.websocket
    javax.websocket-api
    1.0


After setup, Run the application in Tomcat.
  1.  Open browser and try to access application "http://localhost:8080/AppName"
  2.  Now, open firefox browser and try to access application "http://localhost:8080/AppName"
In the browser you will observe that as and when number of connected clients increase, 
the server pushes the total connected client count information on browser as well without explicit request from client

Output:



Number Range Spinner in Angular JS

Using JQuery Datatable in AngularJS application.

Download binary file AngularJS + REST service

Configure Angular2 + Webpack + Maven Sample


Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.

1 comments:

Post a Comment