WebSockets' State of the Union on the JVM with the help of the Atmosphere Framework. Status of atmosphere.js, socketio.js, socks.js client side library discussed as well.
1. WebSockets on the JVM:
Atmosphere to the rescue!
@jfarcand
Async-IO.org, http://async-io.org
CTO
@atmo_framework @jfarcand
2. WebSockets: Myth or Reality
WebSocket a standard? Really?
Tricks for Production Ready
WebSocket Application
@atmo_framework @asyncio
3. WebSockets
is a web technology providing for bi-directional,
full-duplex communications channels
over a single TCP connection.
Polling Long Polling Streaming
Browser Server
request
empty response
request
response
event
Browser Server Browser Server
request
response
request
event
request
response part
event
response part
event
response
request
event
event
WebSocket
Browser Server
request
Response
event
response
event
@atmo_framework @asyncio
4. Agenda
•Who I am
•Atmosphere
•WebSockets: Serveur Side
•WebSocket: Client Side
•Socket.IO and Socks.js
•Conclusion
@atmo_framework @asyncio
5. Who is this strange accent guy
• Creator of Frameworks
• Grizzly (NIO Framework)
• AsyncHttpClient
(HTTP/WebSocket)
• Atmosphere Framework
• Ex-GlassFish, Tomcat & Jetty
« committer »
• Ex Sun Microsystem, France
Telecom, Ning, Sonatype
@atmo_framework @asyncio
6. Currently
•Founder anf CTO Async-
IO.org
•Since 2013
•Atmosphere Support,
Atmosphere Pro & Elite
•Atmosphere is still licenced
Apache 2
@atmo_framework @asyncio
9. WebSockets: Server Side
•Tomcat 7+, Jetty 7+, GlassFish 3+, Resin 2+, JBoss
7.1.2+ native Websocket API
•Non Portable, Unstable API
•Missing Functionality
•What the point of Atmosphere then???????
@atmo_framework @asyncio
16. atmosphere.js
•100% Javascript Library
•Small, portable, mobile optimized
•Transparent Fallback
•One API to Rule them all: WebSockets/Server Sides
Event/Long-Polling/HTML File/JSONP/Polling/Streaming
etc.
@atmo_framework @asyncio
22. Atmosphere Pro!
• atmosphere-satellite: replicate your data and code together In-Memory for
faster execution and seamless elastic scalability across your
Atmosphere's Nodes/Servers.
• atmosphere-tower-control: Monitor your Atmosphere's Node/Server state
via any JMX compliant tool like Java Mission Control. Get statistics on
how many websocket or long-polling clients are currently connected,
add/move connected clients from one node to another, for example in
case of a node being restarted, etc.
• atmosphere-postman: Client/Server extension to Atmosphere to support
message delivery guarantee.
http://async-io.org/AtmospherePro.html
@atmo_framework @asyncio
25. Atmosphere
var socket = atmosphere;
var subSocket;
var request = { url: document.location.toString() + 'chat’, contentType : "application/json”, transport : "websocket" , trackMessageLength :
true };
request.onOpen = function(response) {
content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport }));
};
request.onMessage = function (response) {
var json = atmosphere.util.parseJSON(response.responseBody)
…
};
request.onClose = function(response) {…};
request.onReopen = function(response) {….}
request.onTransportFailure = function(errorMsg, request) {…}
subSocket = socket.subscribe(request);
26. @ManagedService(path = "/chat”)
public class Chat {
@Ready
public void onReady(AtmosphereResource r) {..}
@Disconnect
public void onDisconnect(AtmosphereResourceEvent e) {..}
@Message( encoders = {JacksonEncoder.class},
decoders = {JacksonDecoder.class})
public Reply onMessage(Message message){
return handleAndReply(message);
}
}
Atmosphere
27. Problem #1 – Fallback
•Browser
• Old version
• No support (IE 9)
•Proxys
• Disconnect, block
•Load Balancer
• Breaks Session Affinity
@atmo_framework @asyncio
28. Fallback with Atmosphere
public void onReady(AtmosphereResource r) {
switch (r.transport()) {
case WEBSOCKET:
case SSE:
case LONG-POLLING:
case STREAMING:
case JSONP:
case POLLING:
r.write(“Atmosphere is cool”);
}
}
@atmo_framework @asyncio
29. Atmosphere I/O
•WebSocket uses « non blocking I/O »
•Fallback simulates « non blocking I/O>
Browsers behave the same way as packet are delivered
uniformely.
@atmo_framework @asyncio
31. Protocol Version
•Atmosphere => Transparent Fallback in case the
protocol is not supported
@atmo_framework @asyncio
32. Problem #3 – Lost Lost Lost
• I/O error, websocket message
will be lost.
• Message must be put inside a
cache
• Message must be discarted if
the connection never come
back.
@atmo_framework @asyncio
33. Atmosphere – Messages Lost
@ManagedService(path = "/chat”)
public class Chat {
@Message
public void onMessage(AtmosphereResource r, String message){
// Transparently cache the message in case of a problem
// Transparently write it back once reconnected
r.write(message);
}
}
@atmo_framework @asyncio
34. Problem #4 – Proxy
• Existing Proxy are cutting the
connection.
• Must recover transparently
from a disconnect.
• Heartbeat saves your day!
@atmo_framework @asyncio
36. Problem #5 – New Spec!
• Difference between Tomcat,
Undertow and Jetty already!
• Spec is young, missing fondamental
concepts.
• Tomcat 8.0.12 is stable. GlassFish 4
is dead, Jetty 9.1.3 stable,
Undertow 1.1.Final is stable,
WelLogic is broken.
@atmo_framework @asyncio
37. Problem #5 – JSR 356: Tomcat vs
Jetty
@Message
public void onMessage(String m, Session s) {
for (Session s: sessions.getOpenSessions()){
// Tomcat will throw an IllegalStateException
// if more than one thread call sendXXX.
// Jetty won’t!
session.getAsyncRemote().sendText(m);
}
}
@atmo_framework @asyncio
38. Problem #5 – JSR 356: Tomcat vs
Jetty
private final Semaphore semaphore = new Semaphore(1, true);
@Message
public void onMessage(String m, Session s) {
for (Session s: sessions.getOpenSessions()){
try{
semaphore.acquireUninterruptibly();
session.getAsyncRemote().sendText(m, …);
}finally {
semaphore.release();
}
}
}
@atmo_framework @asyncio
39. Problem #5 – Tomcat vs Jetty
• I/O Event aren’t delivered the same
way.
• CloseReason not the same depending
on the server!!!!
// Hack
if (closeCode == 1000 && getContainerName().contains("Tomcat")) {
closeCode = 1005;
}
@atmo_framework @asyncio
40. Firefox is the new Internet Explorer
6!
// Reload a tab/window
// Firefox => 1001
// Chrome => 1000
if (isFirefox && c.getCode() == CloseReason.GOING_AWAY
|| c.getCode() == CloseReason.NO_STATUS_CODE) {
...
}
@atmo_framework @asyncio
41. Firefox is the new Internet Explorer
6!
Reload in Firefox produces phantom
websockets connections!!!!!!!
@atmo_framework @asyncio
42. Problem #6 – Closing Code
• How to detect if a
websocket was closed by a
Proxy, a Load Balancer or
the Browser!!
@atmo_framework @asyncio
48. W3C API
Ohhhhhhhhh
•Pong/Ping: No exposed
•Headers: Can’t add/read
•Query String: No API, append them to the url
•Cookie: Impossible to read them
@atmo_framework @asyncio
51. Problem #1 – onclose
• Firefox will execute the
ws.onclose function on F5
(reload)
• Chrome/Safari ….. NOT!
@atmo_framework @asyncio
52. Problem #1: onclose
•W3C Specification
ws.onclose = function(closeReason) {
switch(closeReason.code) {
case 1000:
….
}
// Firefox will execute this logic on every reload
// closeReason.wasClean unreliable
if (dirtyClose) {
reconnectTo(…);
}
}
@atmo_framework @asyncio
53. Atmosphere: onclose
•W3C Specification
// Hahahaha go to hell Firefox!!
atmosphere.onClose = function (callback) {
};
@atmo_framework @asyncio
54. Problem #2 – Messages’ length
• Messages can be truncated
when the server write
them
• The Browser received
them in two chunks or I/O
operation
@atmo_framework @asyncio
55. Problem #2: Messages’ length
•W3C Specification
// Craaaaaaashhhhhhhhhhhhh
ws.onmessage = function (callback) {
window.JSON.parse(callback.data);
};
@atmo_framework @asyncio
56. Problem #2: What’s Up, Doctor!
•W3C Specification
// atmosphere.js transparently
// handles it
atmosphere.onMessage = function (callback) {
window.JSON.parse(callback.responseBody);
};
@atmo_framework @asyncio
57. Problem #3 – UUID and Cookie
• No Cookie to identify
the client
@atmo_framework @asyncio
58. Problem #3 – UUID and Cookie
• Solutions:
• Normal request => set-cookie
• Next WebSockets
• Useful if you deploy on
Amazon
(1) HTTP
(2) websockets
@atmo_framework @asyncio
59. Atmosphere: Handshake Protocol
•W3C Specification
T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]
.651|bb7aeeb7-9e44-4aa9-848d-14bba6532de9|1397426374301|
T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]
..
T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]
..
@atmo_framework @asyncio
60. Problem #4 – Proxy
• Proxy can close the websocket or
completely ignore the websocket
handshake, completely fooling the
server…and the browser!
• ws.open never called!!!!
@atmo_framework @asyncio
61. Problem #4 – Proxy
•W3C Specification
websocket.onopen = function (message) {
alert(“Ha ha ha good luck!!!”);
}
websocket.onmessage = function(message) {
// Never called
alert(“Sleep on it!!!”);
}
@atmo_framework @asyncio
62. Problem #4 – Proxy
•W3C Specification
atmosphere.onReopen = function (callback) {
// Yeahhhh!!!
};
atmosphere.onTransportFailure = function (callback) {
// Apache Proxy, I hate you!!!
};
@atmo_framework @asyncio
64. Socket.IO and Socks.js
SockJs et Socket.io
blank slide
for your own
pictures
@atmo_framework @asyncio
65. Socket.IO
• For Node.js
• Streaming, Long-Polling and now Websocket
• Extremely popular, lot of »issues »
602 => https://github.com/LearnBoost/socket.io/issues
• Supported by Atmosphere, both client and server side. Replace
node.js
@atmo_framework @asyncio
66. Socket.IO - Atmosphere
@•ManWag3eCdS Serpveiccief(ipcaatthi o=n "/chat”)
public class Chat {
@Ready
public void onReady(AtmosphereResource r) {..}
@Disconnect
public void onDisconnect(AtmosphereResourceEvent e) {..}
@Message( encoders = {JacksonEncoder.class},
decoders = {JacksonDecoder.class})
public Reply onMessage(Message message){
return handleAndReply(message);
}
}
@atmo_framework @asyncio
67. Socket.IO - Atmosphere
•W3C Specification
var socket = io.connect('', {'resource’:document.location.toString() + 'chat'});
socket.on('connect', function () {
content.html($('<p>',
{ text:'Atmosphere connected using this.socket.transport.name}));
});
socket.on('chat message', function() {
var json = jQuery.parseJSON(msg);
…
}
);
socket.on(‘error’, function (e) {…});
@atmo_framework @asyncio
68. Socks.js
•For Node.js
•Emulate WebSocket, with « fallback »
•Socks.js popularity increase, due to Spring 4, Vert.x
and Atmosphere support
@atmo_framework @asyncio
69. Socks.js - Atmosphere
@•ManWag3eCdS Serpveiccief(ipcaatthi o=n "/clavarder”)
public class Chat {
@Ready
public void onReady(AtmosphereResource r) {..}
@Disconnect
public void onDisconnect(AtmosphereResourceEvent e) {..}
@Message( encoders = {JacksonEncoder.class},
decoders = {JacksonDecoder.class})
public Reply onMessage(Message message){
return handleAndReply(message);
}
}
@atmo_framework @asyncio
70. Socks.js- Atmosphere
•W3C Specification
var socket = new SockJS('http://' + window.location.host + '/chat', null, {
'protocols_whitelist': ['websocket', 'xhr-streaming',
'iframe-eventsource', 'iframe-htmlfile',
'xhr-polling', 'jsonp-polling'] });
socket.onopen = function() {
content.html($('<p>', { text: 'Atmosphere connected using SockJs client'}));
}
socket.onmessage = function (response) {
var message = response.data;
var json = JSON.parse(message);
}
socket.onclose = function() {
}
@atmo_framework @asyncio
71. Conclusion
•WebSockets in Prod without fallback? You’re Crazy!!
•Atmosphere is production ready, and fixes all the
issues listed here!
•What are you waiting for?
@atmo_framework @asyncio