Websocket

The web has been largely built around the so-called request/response paradigm of HTTP. A client loads up a web page and then nothing happens until the user clicks onto the next page. Around 2005, AJAX started to make the web feel more dynamic. Still, all HTTP communication was steered by the client, which required user interaction or periodic polling to load new data from the server.

Technologies that enable the server to send data to the client in the very moment when it knows that new data is available have been around for quite some time. They go by names such as “Push” or “Comet”. One of the most common hacks to create the illusion of a server initiated connection is called long polling. With long polling, the client opens an HTTP connection to the server which keeps it open until sending response. Whenever the server actually has new data it sends the response (other techniques involve Flash, XHR multipart requests and so called htmlfiles). Long polling and the other techniques work quite well. You use them every day in applications such as GMail chat. However, all of these work-arounds share one problem: They carry the overhead of HTTP, which doesn’t make them well suited for low latency applications. Think multiplayer first person shooter games in the browser or any other online game with a realtime component.

WebSocket is a protocol providing full-duplex communications channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API in Web IDL is being standardized by the W3C.

In addition, the communications are done over TCP port number 80, which is of benefit for those environments which block non-web Internet connections using a firewall. WebSocket protocol is currently supported in several browsers including Google Chrome, Internet Explorer, Firefox, Safari and Opera. WebSocket also requires web applications on the server to support it.

WebSocket Attributes:

Following are the attribute of WebSocket object. Assuming we created Socket object as mentioned above:

AttributeDescription
Socket.readyStateThe readonly attribute readyState represents the state of the connection. It can have the following values:
A value of 0 indicates that the connection has not yet been established. A value of 1 indicates that the connection is established and communication is possible. A value of 2 indicates that the connection is going through the closing handshake. A value of 3 indicates that the connection has been closed or could not be opened.
Socket.bufferedAmountThe readonly attribute bufferedAmount represents the number of bytes of UTF-8 text that have been queued using send() method.

WebSocket Events:

Following are the events associated with WebSocket object. Assuming we created Socket object as mentioned above:

EventEvent HandlerDescription
openSocket.onopenThis event occurs when socket connection is established.
messageSocket.onmessageThis event occurs when client receives data from server.
errorSocket.onerrorThis event occurs when there is any error in communication.
closeSocket.oncloseThis event occurs when connection is closed.

WebSocket Methods:

Following are the methods associated with WebSocket object. Assuming we created Socket object as mentioned above:

MethodDescription
Socket.send()The send(data) method transmits data using the connection.
Socket.close()The close() method would be used to terminate any existing connection.

Example:
This is an advance example of taking the snapshot on client side and sending the data to server using websocket.
To capture the client snapshot we used html2Canvas of HTML5.
http://html2canvas.hertzen.com/
https://github.com/niklasvh/html2canvas
//please  download html2ccanvas source file from above link for screencapture functionality and put in webcontent folder with your html files.

Create a dynamic program in Eclipse.
 1)wsocket.html
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>
<!– Arun HTML File –>>
<html>
<head>
<meta charset=”utf-8″>
<title>Tomcat web socket</title>
<script src=”http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.js”></script>
<script type=”text/javascript” src=”html2canvas.js?rev032″></script>
<script type=”text/javascript”>   
var ws = new WebSocket(“ws://localhost:8080/WebSocketSample/wsocket”);
ws.onopen = function () {
    console.log(“Web Socket Open”);
};

   ws.onmessage = function(message) {
       console.log(“MSG from Server :”+message.data);
//document.getElementById(“msgArea”).textContent += message.data + “\n”;   
document.getElementById(“msgArea”).textContent +” Data Send\n”;   
   };
 function postToServerNew(data) {
ws.send(JSON.stringify(data));
document.getElementById(“msg”).value = “”;
}

//Set Interval
setInterval(function(){
 var target = $(‘body’);
   html2canvas(target, {
     onrendered: function(canvas) {
     var data = canvas.toDataURL();
  var jsonData = {
        type: ‘video’,
        data: data,
        duration: 5 ,
        timestamp: 0,     // set in worker
        currentFolder: 0,// set in worker
    };
postToServerNew(jsonData);
   }
 });
},9000);

function closeConnect() {
ws.close();
console.log(“Web Socket Closed: Bye TC”);
}
</script>
</head>

<body>
  <div>
<textarea rows=”18″ cols=”150″ id=”msgArea” readonly></textarea>
</div>
<div>
<input id=”msg” type=”text”/>
<button type=”submit” id=”sendButton” onclick=”postToServerNew(‘Arun’)”>Send MSG</button>
</div>
</body>
</html>

2)
package sample;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;

/**
 * WebSocketServlet is contained in catalina.jar. It also needs servlet-api.jar
 * on build path
 *
 * @author Arun
 *
 */
@WebServlet(“/wsocket”)
public class MyWebSocketServlet extends WebSocketServlet {

    private static final long serialVersionUID = 1L;

    // for new clients, <sessionId, streamInBound>
    private static ConcurrentHashMap<String, StreamInbound> clients = new ConcurrentHashMap<String, StreamInbound>();

    @Override
    protected StreamInbound createWebSocketInbound(String protocol, HttpServletRequest httpServletRequest) {

        // Check if exists
        HttpSession session = httpServletRequest.getSession();

        // find client
        StreamInbound client = clients.get(session.getId());
        if (null != client) {
            return client;

        } else {
            System.out.println(” session.getId() :”+session.getId());
            String targetLocation = “C:/Users/arsingh/Desktop/AnupData/DATA/”+session.getId();
            System.out.println(targetLocation);
            File fs=new File(targetLocation);
            boolean bool=fs.mkdirs();
            System.out.println(” Folder created :”+bool);
            client = new MyInBound(httpServletRequest,targetLocation+”/Output.txt”);
            clients.put(session.getId(), client);
        }

        return client;
    }

    /*public StreamInbound getClient(String sessionId) {
        return clients.get(sessionId);
    }

    public void addClient(String sessionId, StreamInbound streamInBound) {
        clients.put(sessionId, streamInBound);
    }*/
}

3)
package sample;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;

/**
 * Need tomcat-koyote.jar on class path, otherwise has compile error
 * “the hierarchy of the type … is inconsistent”
 *
 * @author Arun
 *
 */
public class MyInBound extends MessageInbound {

    private String name;

    private WsOutbound myoutbound;

    private String targetLocation;

    public MyInBound(HttpServletRequest httpSerbletRequest, String targetLocation) {
        this.targetLocation = targetLocation;
    }

    @Override
    public void onOpen(WsOutbound outbound) {
        System.out.println(“Web Socket Opened..”);
        /*this.myoutbound = outbound;
        try {
            this.myoutbound.writeTextMessage(CharBuffer.wrap(“Web Socket Opened..”));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/

    }

    @Override
    public void onClose(int status) {
        System.out.println(“Close client”);
        // remove from list
    }

    @Override
    protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
        System.out.println(“onBinaryMessage Data”);
        try {
            writeToFileNIOWay(new File(targetLocation), arg0.toString() + “\n”);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            //this.myoutbound.flush();
        }
    }// end of onBinaryMessage

    @Override
    protected void onTextMessage(CharBuffer inChar) throws IOException {
        System.out.println(“onTextMessage Data”);
        try {

            writeToFileNIOWay(new File(targetLocation), inChar.toString() + “\n”);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            //this.myoutbound.flush();
        }
    }// end of onTextMessage

    public void writeToFileNIOWay(File file, String messageToWrite) throws IOException {
        System.out.println(“Data Location:”+file+”            Size:”+messageToWrite.length());
        //synchronized (this){

          byte[] messageBytes = messageToWrite.getBytes();
          RandomAccessFile raf = new RandomAccessFile(file, “rw”);
          raf.seek(raf.length());
          FileChannel fc = raf.getChannel();
          MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_WRITE, fc.position(), messageBytes.length);
          mbf.put(messageBytes);
         fc.close();
        //}


    }//end of method

 }

Author: Arun Singh

Learning is an Habit.