Slide 1

Slide 1 text

WEBSOCKETS Friday, March 2, 12

Slide 2

Slide 2 text

• phpBB • Symfony2 • Silex • Composer igorw @igorwesome Friday, March 2, 12

Slide 3

Slide 3 text

Friday, March 2, 12

Slide 4

Slide 4 text

Friday, March 2, 12

Slide 5

Slide 5 text

WEBSOCKETS Friday, March 2, 12

Slide 6

Slide 6 text

WEB Friday, March 2, 12

Slide 7

Slide 7 text

Application HTTP Presentation TCP Session TCP Transport TCP Network IP Data Link Physical Friday, March 2, 12

Slide 8

Slide 8 text

Application HTTP Presentation TCP Session TCP Transport TCP Network IP Data Link Physical Friday, March 2, 12

Slide 9

Slide 9 text

HTTP Friday, March 2, 12

Slide 10

Slide 10 text

client Friday, March 2, 12

Slide 11

Slide 11 text

request client Friday, March 2, 12

Slide 12

Slide 12 text

reponse client request Friday, March 2, 12

Slide 13

Slide 13 text

THIS IS A GOOD THING Friday, March 2, 12

Slide 14

Slide 14 text

BUT Friday, March 2, 12

Slide 15

Slide 15 text

NOT FOR EVERYTHING Friday, March 2, 12

Slide 16

Slide 16 text

UNIDIRECTIONAL Friday, March 2, 12

Slide 17

Slide 17 text

Friday, March 2, 12

Slide 18

Slide 18 text

LATENCY Friday, March 2, 12

Slide 19

Slide 19 text

STATELESS Friday, March 2, 12

Slide 20

Slide 20 text

Application HTTP Presentation TCP Session TCP Transport TCP Network IP Data Link Physical Friday, March 2, 12

Slide 21

Slide 21 text

Application HTTP Presentation TCP Session TCP Transport TCP Network IP Data Link Physical Friday, March 2, 12

Slide 22

Slide 22 text

WEBSOCKETS Friday, March 2, 12

Slide 23

Slide 23 text

SOCKETS Friday, March 2, 12

Slide 24

Slide 24 text

WEBSOCKETS Friday, March 2, 12

Slide 25

Slide 25 text

PROTOCOL API Friday, March 2, 12

Slide 26

Slide 26 text

THE WEBSOCKET PROTOCOL Friday, March 2, 12

Slide 27

Slide 27 text

browser Friday, March 2, 12

Slide 28

Slide 28 text

Friday, March 2, 12

Slide 29

Slide 29 text

Friday, March 2, 12

Slide 30

Slide 30 text

Friday, March 2, 12

Slide 31

Slide 31 text

• Handshake / Upgrade • TCP • Proxies • Supports TLS (SSL) Friday, March 2, 12

Slide 32

Slide 32 text

Friday, March 2, 12

Slide 33

Slide 33 text

RFC 6455 Friday, March 2, 12

Slide 34

Slide 34 text

COMET Friday, March 2, 12

Slide 35

Slide 35 text

THE WEBSOCKET API Friday, March 2, 12

Slide 36

Slide 36 text

browser Friday, March 2, 12

Slide 37

Slide 37 text

Friday, March 2, 12

Slide 38

Slide 38 text

var ws = new WebSocket('ws://example.org:8080/updates'); ws.onopen = function () { ws.send('hello'); }; ws.onmessage = function (message) { console.log(message.data); }; Friday, March 2, 12

Slide 39

Slide 39 text

JS INTERFACE • WebSocket • onopen • onmessage • onerror • onclose • binaryType • MessageEvent • data Friday, March 2, 12

Slide 40

Slide 40 text

browser API PROTOCOL Friday, March 2, 12

Slide 41

Slide 41 text

Friday, March 2, 12

Slide 42

Slide 42 text

• built on node.js • abstracts socket communication • supports fallback transports Friday, March 2, 12

Slide 43

Slide 43 text

• session storage • namespacing • acknowledgement • broadcasting • reconnection Friday, March 2, 12

Slide 44

Slide 44 text

• json serialization • heartbeats • connection ids • io.sockets collection Friday, March 2, 12

Slide 45

Slide 45 text

4.0+ (2009) 6.0+ (2011) 10.70+ (2012) 5.0+ (2010) 10+ (2012) BROWSER SUPPORT Friday, March 2, 12

Slide 46

Slide 46 text

4.0+ 3.0+ 10.61+ 3.0+ 5.5+ WITH SOCKET.IO Friday, March 2, 12

Slide 47

Slide 47 text

Friday, March 2, 12

Slide 48

Slide 48 text

Y U NO PHP? Friday, March 2, 12

Slide 49

Slide 49 text

Friday, March 2, 12

Slide 50

Slide 50 text

Friday, March 2, 12

Slide 51

Slide 51 text

$context = new ZMQContext(); $sock = $context->getSocket(ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $msg = json_encode([ 'type' => 'debug', 'data' => ['foo', 'bar', 'baz'] ]); $sock->send($msg); Friday, March 2, 12

Slide 52

Slide 52 text

$context = new ZMQContext(); $sock = $context->getSocket(ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $msg = json_encode([ 'type' => 'debug', 'data' => ['foo', 'bar', 'baz'] ]); $sock->send($msg); Friday, March 2, 12

Slide 53

Slide 53 text

$context = new ZMQContext(); $sock = $context->getSocket(ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $msg = json_encode([ 'type' => 'debug', 'data' => ['foo', 'bar', 'baz'] ]); $sock->send($msg); Friday, March 2, 12

Slide 54

Slide 54 text

$context = new ZMQContext(); $sock = $context->getSocket(ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $msg = json_encode([ 'type' => 'debug', 'data' => ['foo', 'bar', 'baz'] ]); $sock->send($msg); Friday, March 2, 12

Slide 55

Slide 55 text

Friday, March 2, 12

Slide 56

Slide 56 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 57

Slide 57 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 58

Slide 58 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 59

Slide 59 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 60

Slide 60 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 61

Slide 61 text

var io = require('socket.io').listen(8080), zmq = require('zmq'), sock = zmq.socket('sub'); sock.subscribe(''); sock.bind('tcp://*:5555'); sock.on('message', function (msg) { var event = JSON.parse(msg); io.sockets.emit(event.type, event.data); }); Friday, March 2, 12

Slide 62

Slide 62 text

var socket = io.connect('http://localhost:8080'); socket.on('debug', function (data) { console.log(data); }); Friday, March 2, 12

Slide 63

Slide 63 text

LE CODE •blog comments •chat •canvas Friday, March 2, 12

Slide 64

Slide 64 text

LE CODE •blog comments •chat •canvas Friday, March 2, 12

Slide 65

Slide 65 text

class CommentController extends Controller { public function createAction(Post $post) { $comment = new Comment(); $comment->setPost($post); $request = $this->getRequest(); $form = $this->createForm(new CommentType(), $comment); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->persist($comment); $em->flush(); $renderedRow = $this->renderView( 'AcmeBlogBundle:Comment:row.html.twig', array('comment' => $comment) ); return new Response($renderedRow, 201); } return new Response('{}', 400, array('Content-Type' => 'application/json')); } } Friday, March 2, 12

Slide 66

Slide 66 text

class CommentController extends Controller { public function createAction(Post $post) { $comment = new Comment(); $comment->setPost($post); $request = $this->getRequest(); $form = $this->createForm(new CommentType(), $comment); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->persist($comment); $em->flush(); $renderedRow = $this->renderView( 'AcmeBlogBundle:Comment:row.html.twig', array('comment' => $comment) ); return new Response($renderedRow, 201); } return new Response('{}', 400, array('Content-Type' => 'application/json')); } } Friday, March 2, 12

Slide 67

Slide 67 text

Secret Sauce Friday, March 2, 12

Slide 68

Slide 68 text

private function publishCommentCreate(Comment $comment) { $context = new \ZMQContext(); $sock = $context->getSocket(\ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $renderedRow = $this->renderView( 'AcmeBlogBundle:Comment:row.html.twig', array('comment' => $comment) ); $postId = $comment->getPost()->getId(); $msg = json_encode(array( 'type' => "post.$postId.comment.create", 'data' => $renderedRow, )); $sock->send($msg); } Friday, March 2, 12

Slide 69

Slide 69 text

private function publishCommentCreate(Comment $comment) { $context = new \ZMQContext(); $sock = $context->getSocket(\ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $renderedRow = $this->renderView( 'AcmeBlogBundle:Comment:row.html.twig', array('comment' => $comment) ); $postId = $comment->getPost()->getId(); $msg = json_encode(array( 'type' => "post.$postId.comment.create", 'data' => $renderedRow, )); $sock->send($msg); } Friday, March 2, 12

Slide 70

Slide 70 text

private function publishCommentCreate(Comment $comment) { $context = new \ZMQContext(); $sock = $context->getSocket(\ZMQ::SOCKET_PUB); $sock->connect('tcp://127.0.0.1:5555'); $renderedRow = $this->renderView( 'AcmeBlogBundle:Comment:row.html.twig', array('comment' => $comment) ); $postId = $comment->getPost()->getId(); $msg = json_encode(array( 'type' => "post.$postId.comment.create", 'data' => $renderedRow, )); $sock->send($msg); } Friday, March 2, 12

Slide 71

Slide 71 text

$this->publishCommentCreate($comment); Friday, March 2, 12

Slide 72

Slide 72 text

var socket = io.connect('http://localhost:8080'); socket.on('post.'+postId+'.comment.create', function (data) { renderComment(data); }); Friday, March 2, 12

Slide 73

Slide 73 text

LE CODE •blog comments •chat •canvas Friday, March 2, 12

Slide 74

Slide 74 text

Send Friday, March 2, 12

Slide 75

Slide 75 text

var socket = io.connect('http://localhost:8080'), messages = $('.messages'); socket.on('message', function (message) { var messageHtml = $('
').text(message.body); messages.append(messageHtml); messages.prop('scrollTop', 100000); }); Friday, March 2, 12

Slide 76

Slide 76 text

var socket = io.connect('http://localhost:8080'), messages = $('.messages'); socket.on('message', function (message) { var messageHtml = $('
').text(message.body); messages.append(messageHtml); messages.prop('scrollTop', 100000); }); Friday, March 2, 12

Slide 77

Slide 77 text

var form = $('form'); form.submit(function (event) { event.preventDefault(); var input = form.find('*[name=message]'), body = input.val(); if (!body.length) { return; } socket.emit('message', { name: name, body: body }); input.val(''); }); Friday, March 2, 12

Slide 78

Slide 78 text

var form = $('form'); form.submit(function (event) { event.preventDefault(); var input = form.find('*[name=message]'), body = input.val(); if (!body.length) { return; } socket.emit('message', { name: name, body: body }); input.val(''); }); Friday, March 2, 12

Slide 79

Slide 79 text

var io = require('socket.io').listen(8080); io.sockets.on('connection', function (socket) { socket.on('message', function (message) { io.sockets.emit('message', message); }); }); Friday, March 2, 12

Slide 80

Slide 80 text

var io = require('socket.io').listen(8080), messages; messages = []; io.sockets.on('connection', function (socket) { messages.forEach(function (message) { socket.emit('message', message); }); socket.on('message', function (message) { io.sockets.emit('message', message); messages.push(message); }); }); Friday, March 2, 12

Slide 81

Slide 81 text

var io = require('socket.io').listen(8080), messages; messages = []; io.sockets.on('connection', function (socket) { messages.forEach(function (message) { socket.emit('message', message); }); socket.on('message', function (message) { io.sockets.emit('message', message); messages.push(message); }); }); Friday, March 2, 12

Slide 82

Slide 82 text

var io = require('socket.io').listen(8080), bufferLimit = 15, messages; messages = []; io.sockets.on('connection', function (socket) { messages.forEach(function (message) { socket.emit('message', message); }); socket.on('message', function (message) { io.sockets.emit('message', message); messages.push(message); if (messages.length > bufferLimit) { messages = messages.splice(-bufferLimit, bufferLimit); } }); }); Friday, March 2, 12

Slide 83

Slide 83 text

var io = require('socket.io').listen(8080), bufferLimit = 15, messages; messages = []; io.sockets.on('connection', function (socket) { messages.forEach(function (message) { socket.emit('message', message); }); socket.on('message', function (message) { io.sockets.emit('message', message); messages.push(message); if (messages.length > bufferLimit) { messages = messages.splice(-bufferLimit, bufferLimit); } }); }); Friday, March 2, 12

Slide 84

Slide 84 text

LE CODE •blog comments •chat •canvas Friday, March 2, 12

Slide 85

Slide 85 text

USE CASES •Games •Notifications •Collaboration •Statistics •Chat Friday, March 2, 12

Slide 86

Slide 86 text

PUB/SUB Friday, March 2, 12

Slide 87

Slide 87 text

Push only? Friday, March 2, 12

Slide 88

Slide 88 text

EventSource. Friday, March 2, 12

Slide 89

Slide 89 text

LINKS • tools.ietf.org/html/rfc6455 • dev.w3.org/html5/websockets • developer.mozilla.org/en/WebSockets • socket.io • github.com/igorw/websockets-talk Friday, March 2, 12

Slide 90

Slide 90 text

github.com/igorw/websockets-talk Friday, March 2, 12

Slide 91

Slide 91 text

CREDITS • thenounproject.com • stopwatch • lightning • sync • refresh Friday, March 2, 12

Slide 92

Slide 92 text

Questions? @igorwesome speakerdeck.com /u/igorw joind.in/5997 Frögli? Friday, March 2, 12