+ All Categories
Home > Documents > Speed up Your Web Applications with HTML5 WebSockets...

Speed up Your Web Applications with HTML5 WebSockets...

Date post: 29-May-2018
Category:
Upload: vancong
View: 223 times
Download: 0 times
Share this document with a friend
39
Speed up Your Web Applications with HTML5 WebSockets Yakov Fain, Farata Systems, USA
Transcript

Speed up Your Web Applications with HTML5 WebSockets

Yakov Fain, Farata Systems, USA

The Plan

- HTTP request-response

- Demo

- Server-Sent Events

- Demo

- WebSocket

- Demo

What Do You See?

HTTP Hacks

• Polling

•  Long Polling

• Streaming

Polling

Long Polling

Streaming

Getting Price Quotes from Google Finance

HTTP Request Response Demo

Introducing the Demo The Software The Server: GlassFish 4 (promoted build B88), Oracle The server-side Java app can generate random price quotes The Client: HTML5 Ext JS framework, Sencha The Browser: Chrome , Google Charles Proxy The Goal 1. The server generates random stock prices for a 12-stock portfolio 2. The user sends a request for price quote for a stock 3. The HTML client displays the received price 4. Observe what went over the network

The Server: Rest @Path("stock") public class RestResource { @GET @Produces(value = MediaType.APPLICATION_JSON) @Path("/{ticker}") public String getRandomValue(@PathParam(value = "ticker") String ticker) { return new Gson().toJson(RandomStocksGenerator.getDataForTicker(ticker)); } }

The Client: AJAX in Ext JS 'mypanel button[action=doRestCall]': click: this.onRestCall }

onRestCall: function (btn) { var ticker = Ext.ComponentQuery.query('mypanel textfield[name=ticker]')[0].getValue(); var rest_url = "http://" + document.location.host + document.location.pathname + "rest/stock/"; rest_url = rest_url + ticker; Ext.Ajax.request({ url: rest_url, scope: this, success: function (response) { var a = Ext.JSON.decode(response.responseText); a.price = parseFloat(a.price).toFixed(4); console.log(a); } });

Server-Sent Events

What’s SSE

•  It’s not a request-response mode

•  The browser subscribes to events from server by creating EventSource pointing to this server

•  The server can send data to client at any time

•  The browser receives an event + data

Browser Subscribes to SSE var source = new EventSource('http://localhost:8080/stock/events'); source.addEventListener('open', function(e) { // Connection was opened. }, false); source.addEventListener(’priceChanged', function(e) { var priceQuote = JSON.parse(e.data); … }, false); source.addEventListener('error', function(e) { if(e.readyState == EventSource.CLOSED) { // Connection was closed. } }, false);

To listen to any messages: source.onmessage = function(e) {….};

Pushing SSE from Server

The server sends events as text messages with MIME `text/event-stream`. Each message starts with data: and end with a pair /n/n: 'data: {"price": "123.45"}/n/n` The browser concatenates all these messages separating them with /n.

Pushing from Glassfish (Jersey) @Path("stock") public class SseResource { private static final SseBroadcaster BROADCASTER = new SseBroadcaster(); private boolean isRunning = false; private Timer broadcastTimer; @GET @Path("stock-generator") @Produces(SseFeature.SERVER_SENT_EVENTS) public EventOutput itemEvents() { final EventOutput eventOutput = new EventOutput(); BROADCASTER.add(eventOutput); if (!isRunning) startBroadcastTask(); return eventOutput; }

Broadcasting in Jersey protected void startBroadcastTask() { broadcastTimer = new Timer(); broadcastTimer.schedule( new SseBroadcastTask(BROADCASTER, 0), 0, 300); this.isRunning = true; }

public class SseBroadcastTask extends TimerTask { private final SseBroadcaster owner; public SseBroadcastTask(SseBroadcaster owner, int timeout) { this.owner = owner; } @Override public void run() { OutboundEvent event = new OutboundEvent.Builder().data( String.class, RandomStocksGenerator.getRandomValues().toJson()).build(); owner.broadcast(event); …

Push With Serer-Sent Events Demo

Introducing the SSE Demo The Software The Server: GlassFish 4 (promoted build B88), Oracle The Java app can generate random price quotes The Client: HTML5 Ext JS framework, Sencha The Chrome Browser, Google

The Goal 1. The server generates random stock prices for a 12-stock portfolio 2. The server pushes 3 price quotes per second using SSE 3. The HTML client shows the prices in a data grid

WebSocket

WebSocket

•  Standard W3C protocol (RFC6455)

•  Java EE 7 includes WebSocket API (JSR-356)

•  Web Browsers include window.WebSocket object. No plugins required.

How WebSocket Works

Establish a socket connection via HTTP for the initial handshake.

Switch the protocol from HTTP to a socket-based protocol.

Send messages in both directions simultaneously.

This is not a request-response model!

Protocol Upgrade: HTTP à WebSocket

•  Client sends Upgrade HTTP-request •  Server confirms Upgrade

•  Client receives Upgrade response from server •  Client changes WebSocket.readyState to open

HTTP://… HTTPS://…

WS://… WSS://…

URI Schemes

The wss encryption is done the same way as in https

W3C: WebSocket Interface [Constructor(DOMString url, optional (DOMString or DOMString[]) protocols)] //<1> interface WebSocket : EventTarget { readonly attribute DOMString url; const unsigned short CONNECTING = 0; const unsigned short OPEN = 1; const unsigned short CLOSING = 2; const unsigned short CLOSED = 3; readonly attribute unsigned short readyState; readonly attribute unsigned long bufferedAmount; // networking [TreatNonCallableAsNull] attribute Function? onopen; [TreatNonCallableAsNull] attribute Function? onerror; [TreatNonCallableAsNull] attribute Function? onclose; readonly attribute DOMString extensions; readonly attribute DOMString protocol; / void close([Clamp] optional unsigned short code, optional DOMString reason); // messaging [TreatNonCallableAsNull] attribute Function? onmessage; attribute DOMString binaryType; void send(DOMString data); void send(ArrayBufferView data); void send(Blob data); };

@ServerEndpoint in Java EE

Client

Your Java Endpoint and other classes

POJO Decoder

Encoder

WebSocket Endpoint @ServerEndpoint(value = "/stock-generator", encoders = { StockMessageEncoder.class }, decoders = { StockMessageDecoder.class }) public class StocksEndpoint { @OnOpen public void onOpen(Session session) { … } @OnMessage public void onMessage(StockMessage message, Session client) { } @OnClose public void onClose(Session session) {… … } … }

public class StockMessageDecoder implements Decoder.Text<StockMessage> { @Override public StockMessage decode(String s) throws DecodeException { Gson gson = new Gson(); return gson.fromJson(s, StockMessage.class); } … }

public class StockMessageEncoder implements Encoder.Text<StockMessage> { @Override public String encode(StockMessage object) throws EncodeException { return new Gson().toJson(object); } … }

Decoder

Encoder

Heartbeats: Pings and Pongs

Heartbeats is a mechanism to check that connection is still alive. If a WebSocket implementation receives a ping it has to respond with a pong ASAP.

There is no JavaScript API to support Pings and Pongs.

Web Socket Demo

The Software The Server: GlassFish 4 (promoted build B88), Oracle The Java app can generate random price quotes The Client: HTML5 Ext JS framework, Sencha The Chrome Browser, Google Charles proxy

Introducing the WebSocket Demo

The Goal 1. The server generates random stock prices for a 12-stock portfolio 2. The server pushes 20 price quotes per second using WebSocket 3. The HTML client shows the prices in a data grid

What was Pushed via WebSocket

The size of each data push: The length price quote data: from 42 to 45 bytes WebSocket added overhead: 2 bytes

{"symbol": "APPL", "id": 555, "price": "451.29"}

Comparing Overheads Http Request-Response Each roundtrip has: request header: 429 bytes + 268 bytes response header + 46 bytes data Server-Sent Events Initial request header 406 bytes + 268 bytes response header Each push: 46 bytes data + 8 bytes message wrapper WebSocket Initial upgrade request: 406 bytes + 268 bytes Each push 46 bytes data + 2 bytes message wrapper It’s full-duplex, not HTTP-based, works much faster.

Caniuse.com: Browser Support

Reducing kilobytes of data to 2 bytes... and reducing latency from 150ms to 50 ms is far more than marginal. In fact, these two factors alone are enough to make WebSocket seriously interesting to Google.

Ian Hickson, Google

The unedited drafts of the book Enterprise Web Development are published at enterprisewebbook.com.

Contact Info

Farata Systems: faratasystems.com

Personal blog: yakovfain.com

Twitter: @yfain

Podcasts in Russian: americhka.us

Thank you!


Recommended