Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WebSockets and Server-Sent Events

WebSockets and Server-Sent Events

Presentation held at Framsia, a JavaScript meetup in Oslo, Norway, and BartJS, a JavaScript meetup in Trondheim, Norway.

Kim Joar Bekkelund

October 30, 2013
Tweet

More Decks by Kim Joar Bekkelund

Other Decks in Programming

Transcript

  1. Polling HTTP overhead per message – Polling logic in the

    client – 1 GET = 1 HTTP request and maybe data
  2. Long-polling Client Server 30s (function poll(){ $.ajax({ url: "/some-url", dataType:

    "json", timeout: 30000, success: function(data) { // handle data }, complete: poll }); })();
  3. Long-polling Client Server 30s (function poll(){ $.ajax({ url: "/some-url", dataType:

    "json", timeout: 30000, success: function(data) { // handle data }, complete: poll }); })();
  4. Long-polling Less HTTP overhead + Polling logic in the client

    – 1 GET = 1 HTTP request and often data
  5. WebSockets Bidirectional Server and client can send and receive Full-duplex

    Server and client can send at the same time Not HTTP Minimal overhead per message Across domains No same-origin policy No constraint on payload Handles both text and binary data
  6. var ws = new WebSocket('ws://localhost:8123'); ws.onopen = function() { ws.send('yay!

    we connected!'); }; ws.onmessage = function(event) { console.log('Received from server: ' + event.data); }; HTML
  7. var WebSocketServer = require('ws').Server; var wss = new WebSocketServer({ port:

    8123 }); wss.on('connection', function(ws) { ws.send('Server says hello'); ws.on('message', function(message) { console.log('Received from client:', message); }); }); app.js
  8. var WebSocketServer = require('ws').Server; var wss = new WebSocketServer({ port:

    8123 }); wss.on('connection', function(ws) { ws.send('Server says hello'); ws.on('message', function(message) { console.log('Received from client:', message); }); }); app.js node app.js
  9. WebSocket Protocol (IETF) RFC6455 “Minimalistic” protocol above TCP Starts out

    as HTTP Designed to work on port 80 and 443 Defines new URL schema: ws and wss
  10. WebSocket Protocol (IETF) Request GET / HTTP/1.1 Host: localhost:8123 Origin:

    http://localhost:8000 Connection: Upgrade Upgrade: websocket Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 Response HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  11. WebSocket Protocol (IETF) Request Response HTTP/1.1 101 Switching Protocols Upgrade:

    websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= GET / HTTP/1.1 Host: localhost:8123 Origin: http://localhost:8000 Connection: Upgrade Upgrade: websocket Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
  12. +

  13. “The protocol is designed to allow for extensions, which will

    add capabilities to the base protocol.”
  14. No multiplexing Client Server Head-of-Line Blocking – all others are

    blocked “A Multiplexing Extension for WebSockets” large message
  15. var ws = new WebSocket(url[, protocols]); ws.onopen = function(e) {

    }; ws.onmessage = function(e) { console.log(e.data) }; ws.onerror = function(e) { console.log(e.code, e.reason) }; ws.onclose = function(e) { }; ws.send(message); (W3C) WebSocket API
  16. var ws = new WebSocket(url[, protocols]); ws.onmessage = function(msg) {

    if (msg.data instanceof Blob) { processBlob(msg.data); } else { processText(msg.data); } }; (W3C) WebSocket API
  17. ws.send(message); ws.send(message); ws.send(message); ws.send(message); … ws.send(message); ws.send(message); ws.send(message); ws.send(message); if

    (ws.bufferedAmount < threshold) { ws.send(message); } THROTTLING LOW-LEVEL ABSTRACTION beware of how much data you send
  18. Channels Group several events When >1 thing on the socket

    LOW-LEVEL ABSTRACTION the usual patterns
  19. Request/response When you need to ACK a message Or when

    you’re waiting for a success or error LOW-LEVEL ABSTRACTION the usual patterns
  20. Firehose When you want to push EVERYTHING as it’s happening

    LOW-LEVEL ABSTRACTION the usual patterns
  21. var io = require('socket.io').listen(8123); io.sockets.on('connection', function(socket) { socket.emit('meetup', { name:

    'framsia!' }); socket.on('other-event', function(data) { console.log(data); }); }); BACKEND
  22. var source = new EventSource('/stream'); source.onopen = function(e) { console.log('opened');

    } source.addEventListener('open', function(e) { console.log('opened'); }, false); source.addEventListener('message', function(e) { console.log(e.data); }, false); FRONTEND
  23. var http = require('http'); var express = require('express'); BACKEND var

    app = express(); app.use(express.static('./public')); http.createServer(app).listen(8123); app.get('/stream', function(req, res) { req.socket.setTimeout(Infinity); }); res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); res.write('\n'); var messageCount = 0; setInterval(function() { messageCount++; res.write('id: ' + messageCount + '\n'); res.write('data: msg ' + messageCount + '\n\n'); }, 1000); res.write('data: testing\n\n');
  24. Need more than one channel? var source = new EventSource('/stream');

    source.addEventListener('message', function(e) { console.log(e.data); }, false); source.addEventListener('userlogon', function(e) { console.log('login', e.data); }, false); REGULAR MESSAGE data: msg 1\n\n WITH EVENT NAME event: userlogon\n data: kimjoar\n\n
  25. Server-Sent Events WebSockets Bidirectional & full duplex Better browser-support Handles

    binary data Automatic reconnect Simpler protocol Just HTTP