2. Two words about myself
Currently freelancing and working on my own ideas.
…one of which involves and WebSockets!
Bicycle Touring Amsterdam
3. Agenda
• What are WebSockets?
• WebSocket clients
• Relationship and comparison with HTTP
• Advantages and disadvantages
• WebSocket servers in Play!
• Simple examples & exercises
• Use case
4. What are WebSockets?
• Full-duplex channel between client and server.
• Persistent connection. Both parties can send data
at any time.
• Very simple API.
• Standardised by the IETF as RFC 6455 in 2011,
which has lead to broader adoption.
6. The API, Client-side
RECEPTION CALLBACKS
• onOpen
• onClosed
• onMessage(message)
• onError(error)
CONNECTION
• open
• close
SEND DATA
• send(message)
7. var myWebSocket = new WebSocket("ws://fabio.com/example");
// define callbacks
myWebSocket.onmessage = function(event) {
console.log("got data: " + event.data);
}
myWebSocket.onopen = function(event) {
console.log("Connection open ...");
};
myWebSocket.onclose = function(event) {
console.log("Connection closed.");
};
myWebSocket.onerror = function(event) {
console.log("Error!");
};
myWebSocket.send("Hello from Javascript!”); // send stuff
myWebSocket.close(); // close connection
JavaScript client example
8. WebSocketClient mWsClient = new WebSocketClient(URI.create(“ws://fabio.com/example”), new
Listener() {
@Override
public void onMessage(final String message) {
Log.d(TAG, “onMessage: ” + message);
}
@Override
public void onError(final Exception error) {
Log.e(TAG, "Error!", error);
}
@Override
public void onDisconnect(final int code, final String reason) {
Log.d(TAG, String.format("Disconnected! Code: %d Reason: %s", code, reason));
}
@Override
public void onConnect() {
Log.d(TAG, "onConnect");
}
}, mExtraHeaders);
mWsClient.connect();
mWsClient.send(“Hello from Android!”);
mWSClient.disconnect();
Android (Java) client example
9. Request URL:ws://echo.websocket.org/
Request Method:GET
Status Code:101 Web Socket Protocol Handshake
Connection:Upgrade
Host:echo.websocket.org
Sec-WebSocket-Version:13
Upgrade:websocket
Relationship with HTTP
• A websocket connection is initiated via a
standard HTTP GET request, where the client
asks for an ‘Upgrade’
• The response will be a 101 status, ‘Switching
protocol’
10. Why WebSockets?
• The ‘native’ web built around HTTP only relies on
client’s action. Only the client can request new content
by for instance opening a new page.
• A way to make things more dynamic is using intense
polling, which is bad for performance and traffic.
• The need to give impression of a ‘dynamic’ web was
solved using workarounds like Long-polling or
Streaming.
• It works but it’s complicated and it doesn’t solve the
big issue of the HTTP overhead!
11. WS vs HTTP: overhead
HTTP: up to 2000 bytes (2Kb)
WebSocket: 2 bytes
13. Downsides of WebSockets
• You need to build your own protocol, even for the
simplest thing! You cannot use any of the friendly
HTTP statuses, body etc. Lower level of abstraction.
• If your application doesn’t require a lot of dynamic
interaction, HTTP is much simpler to implement.
• Regular sockets vs WebSockets: plain TCP is even
faster, but very low level (difficult to access).
14. A few useful links
• https://tools.ietf.org/html/rfc6455 (official doc)
• http://www.html5rocks.com/en/tutorials/websockets/
basics/ (basic tutorial)
• http://www.websocket.org (the echo server folks)
• http://blog.arungupta.me/2014/02/rest-vs-websocket-
comparison-benchmarks/ (HTTP vs WebSocket
comparison)
• http://eng.42go.com/websockets-vs-regular-sockets/
15. WebSockets in Play!
Similar signature to a regular HTTP Action:
val echo = Action { request =>
Ok("Got request [" + request + "]")
}
def index = WebSocket.using[String] { request =>
val in = Iteratee.foreach[String](chunk => println(chunk))
val out = Enumerator("Hello!")
(in, out)
}
using[A](f: (RequestHeader) (Iteratee[A, _], Enumerator[A]))
WebSocket.using signature:
16. WebSockets in Play!
There is also an ‘async’ version which combines the
two channels asynchronously and returns a Future.
def index = WebSocket.async[String] { request =>
Future {
val in = Iteratee.foreach[String](chunk => println(chunk))
val out = Enumerator("Hello!")
(in, out)
}
}
async[A](f: (RequestHeader) Future[(Iteratee[A, _], Enumerator[A])])
WebSocket.async signature:
17. Iteratees and Enumerators
• Complex functional abstractions. Very powerful but
difficult to grasp.
• In the WebSocket domain, all you need to know is that
they represent the two channels where data flows
between client and server.
18. Iteratees & Enumerators
How To
• They both take a type:
• Play! Framework provides various utilities to create
them and use them together.
• Time for some concrete examples!
trait Iteratee[E, +A] extends AnyRef
trait Enumerator[E] extends AnyRef
19. Repositories
(ask Google for “ticofab github” or something like that)
• https://github.com/ticofab/simple-websocket-client
(test client)
• https://github.com/ticofab/simple-play-websocket-
server (test server)
20. WebSockets in Play!
Even though you can wrap the pair (Iteratee, Enumerator) into
an Actor, the framework also offers a way to manage a
WebSocket using actors out of the box. The signature of the
accept function is unusual: a function that returns a function
which takes an ActorRef and returns the Props of an actor!
acceptWithActor[A, B](f: (RequestHeader) (ActorRef) Props)
There is also a way to reject a Websocket connection:
tryAcceptWithActor[A, B](f: (RequestHeader) Future[Either[Result,
(ActorRef) Props]])
Return Left to reject or Right(WebsocketActor.Props) to accept.
21. def index = WebSocket.acceptWithActor[String, String] { request => out =>
WebsocketActor.props(out)
}
object MyWebSocketActor {
def props(out: ActorRef) = Props(new WebsocketActor(out))
}
class WebsocketActor(out: ActorRef) extends Actor {
def receive = {
case msg: String =>
out ! ("I received your message: " + msg)
}
}
WebSockets in Play!
22. Little exercise
1. Uses Actors to handle connections wrapping Iteratee and
Enumerators.
2. It echoes anything it receives, but closes the connection if it
receives a specific string of your choice.
3. Bonus: make the endpoint proxy the result of the API call to:
Create a new Play! app with a WebSocket endpoint.
http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl
23. Two good articles
• Iteratees and Enumerators for human beings: http://
mandubian.com/2012/08/27/understanding-play2-
iteratees-for-normal-humans/
• WebSocket examples: http://blog.tksfz.org/
2012/10/12/websockets-echo-using-play-scala-
and-actors-part-i/