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.

Avatar for Kim Joar Bekkelund

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