Sunday, September 14, 2014

Working with WebSocket

Before jumping into the WebSocket, I would like to briefly describe about the traditional request/response pattern. In traditional request/response pattern - client will request a resource from the server and server will respond back to the client with the resource. So, at a time one operation is being performed, it may be request or response. This mechanism is sometime called "Half Duplex" communication. 

WebSocket is also followed the same pattern but it is based on "Full Duplex" communication.

What is WebSocket

WebSocket is a communication protocol. It is full duplex communication protocol. It is working on top of TCP connection. WebSocket was designed to be work with Web Browsers and Web Servers.

In the traditional request-response model, the client requests resources, and the server provides responses. The exchange is always initiated by the client; the server cannot send any data without the client requesting it. This model worked well when clients made occasional requests for documents that changed infrequently, but the limitations of this approach are increasingly relevant as content changes quickly and users expect a more interactive experience on the Web. 

The WebSocket protocol addresses these limitations by providing a full-duplex communication channel between the client and the server. Currently WebSocket can be implemented using JavaScript, HTML5, Java etc.


Technical Details

WebSocket is working in client/server model. In WebSocket, WebSocket server publishes a endpoint and WebSocket client uses endpoint Url to invoke the server endpoint. After connection is established then 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. 

An example handshake from a client looks like this:

GET /path/to/websocket/endpoint HTTP/1.1Host: localhostUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==Origin: http://localhostSec-WebSocket-Version: 13

An example handshake from the server in response to the client looks like this:
HTTP/1.1 101 Switching Protocols

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

Handshaking Process

After getting the handshaking request from the client. Server applies a known operation to the HTTP header named Sec-WebSocket-Key. The server sends back new value to 
Sec-WebSocket-Accept HTTP header. Once the client got the response back from the server, client applies the same operation to Sec-WebSocket-Key HTTP header. After that client will check the new value with the value of HTTP header named 
Sec-WebSocket-Accept. If both the values are matching then connection from the client to server is established.

WebSocket supports text messages (encoded as UTF-8) and binary messages. 

The control frames in WebSocket are closeping, and pong (a response to a ping frame). Ping and pong frames may also contain application data.

WebSocket connection URI is given below. There are two flavour of WebSocket connection.

1. ws://localhost:8798/websockets/message - ws scheme is the unencrypted WebSocket connection to the server. It is similar to http scheme, if no port number is specified then will consider port 80.
2. wss://localhost:8798/websockets/message - wss scheme is the encrypted WebSocket connection to the server. It is similar to https scheme. If no port number is specified then will consider port 443.

Data transfer

Using WebSocket we can send data of type Text, Binary and Ping/Pong

WebSocket Life Cycle

In order to work with WebSocket, we have to deal with couple of WebSocket's life cycle methods. Life cycle callback methods are given below:

1. onOpen - Called during connection open.
2. onMessage - Called during message received.
3. onClose - Called during connection close.
4. onError - Called when error occurred in connection.


WebSocket Endpoint Designing approach

There are two approaches of designing WebSocket Endpoint. 

1. Programmatic Endpoint - To work with programmatic endpoint, endpoint have to extends from Endpoint class from package javax.websocket. The Endpoint class has only one abstract method i.e onOpen. So, you have to implement that. Also we have to implement onMessage method of message handler. To add message handler, we can use session object's addMessageHandler method.

2. Annotated Endpoint - To work with annotated endpoint, endpoint have to use some pre-defined annotations defined in package javax.websocket and javax.websocket.server. Following are the annotations need to use during defining Annotation based Endpoint. One important thing is that - if you choose annotation based implementation then you do not have to implement any message handler in order to use onMessage life cycle callback method.

1. @javax.websocket.server.ServerEndpoint - It is a class level annotation.
2. @javax.websocket.onOpen
3. @javax.websocket.onMessage
4. @javax.websocket.onClose
5. @javax.websocket.onError

WebSocket Supports

1. WebSocket API supports to maintain client state using session object. We will get session object in all life cycle callback methods.
2. WebSocket API also supports Encoders and Decoders message. Encoding helping to convert java object to WebSocket message. Decoding helping the reverse operation.
3. WebSocket allow us to use Path Parameters while declaring WebSocket Server Endpoint. After that we can use that parameter in any of the life cycle callback methods using @javax.websocket.server.PathParam annotation.
4. Better error handling using one of the life cycle callback method during connection problem, runtime error, error during conversion(encoding, decoding).
5. Supports granular level endpoint configuration.



For practical example please check this blog.