SlideShare a Scribd company logo
Stas Zozulja
stas.z@smart-gamma.com
Real-Time Web applications
with WebSockets
About me
● WEB developer since 2009
● Symfony developer at SmartGamma
since 2013
● https://github.com/stas-zozulja
● https://www.facebook.com/stas.zozulj
a
Real-Time Web applications with Websocket
Real-Time Web applications with Websocket
Agenda
● What is Real-Time Web?
● Transport mechanisms
● Real-Time in PHP (Ratchet)
● && everywhere (Pushpin)
What is Real-Time ?
https://www.leggetter.co.uk/2016/04/22/what-is-realtime.html
● Hard real-time
- missed deadline?
System fault
● Firm real-time
- missed?
Result is zero
● Soft real-time
- missed?
quality degrades
it's all about deadline
and Real-Time Web?
Server pushes a data to Clients when some event
occurs, while Clients does not need to poll a server for
new data.
it's all about Push
https://www.leggetter.co.uk/2016/04/22/what-is-realtime.html
Do I need real-time?
YES! You do!
● Better UX - instant data updates
● Chatting, notification, signaling
● Activity streams
● Data visualization
● User collaboration
Transport mechanisms
● Long polling
● HTTP streaming
● WebSockets
Long polling
Delayed HTTP request. After response (or timeout)
new request is opening by client.
● Uni-directional
● Overhead
(headers in each request)
HTTP Streaming
Request that never ends, response content is
chunked in portions, usually JSON. Only one
direction.
WebSocket protocol
Protocol providing bidirectional communication
channel over a single TCP connection.
WebSocket handshake
Request:
GET /chat HTTP/1.1
Host: ws.example.com:8080/chat
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: T6IDGBEmb...
Connection: Upgrade
Upgrade: websocket
Response:
HTTP/1.1 101 Switching protocols
Connection: Upgrade
Sec-WebSocket-Accept: xTComwY...
Upgrade: websocket
X-Powered-By: Ratchet/0.3.4
ws://
wss://
https://tools.ietf.org/html/rfc6455
http://caniuse.com/#feat=websockets
Support:
● IE 10+
● FF 6+
● Chrome 14+
● iOS 4.2+
● Android 4.4+
● Safari 5+
Our context
● Live streaming app
● REST API for mobile clients (iOS, Android)
● WEB part
● Build Real-time counter of viewers
or
Ratchet - WebSockets for PHP
http://socketo.me/
Built on top of ReactPHP
Components:
● I/O (socket transport) – IOServer
● HTTP Protocol handler – HTTPServer
● WebSocket Protocol Handler – WSServer
● SessionProvider – Symfony Session
● WAMP Protocol Handler – WampServer
+
● Your Application
MessageComponentInterface implementation
http://reactphp.org/
& Step 1. Implement MessageComponentInterface
& Step 2. onMessage()
& Step 3. Write Console command that runs a server
& Next steps. WAMP Subprotocol.
● WAMP – Web Application Messaging
Protocol.
● RPC and Pub/Sub patterns
● Autobahn client libraries
http://wamp-proto.org/
http://autobahn.ws/
&
Cons
● Horizontally scaling is hard
need to share a Connections between nodes
● One exception can stop whole server
Use supervisord, try...catch, test Your code
Pros
● Its PHP!
● Easy to implement and use existing code
https://www.leggetter.co.uk/real-time-web-technologies-guide/
j.mp/realtime-tech-guide
https://fanout.io/
Pushpin
a reverse proxy for the real-time Web
http://pushpin.org/
● Pub/Sub
● Long polling, HTTP Streaming or WebSockets
● Works with any backend
● Your API can be real-time with HTTP streaming
● WebSocket over HTTP – what? :)
https://fanout.io/
Pushpin installation
Debian, Ubuntu:
sudo apt-get install pushpin
sudo service pushpin start
http://pushpin.org/docs/#install
MacOS X:
brew install pushpin
pushpin
Pushpin configuration
routes config file:
* localhost:80,over_http
● route all connections from Pushpin to
your backend
● over_http option to enable
WebSocket-over-HTTP protocol
https://github.com/fanout/pushpin/wiki
https://github.com/fanout/pushpin/blob/master/docs/websocket-over-http.md
WebSocket-over-HTTP (GRIP protocol)
Pushpin encodes WebSocket events into a regular HTTP
requests and passes them to your backend.
Events are:
OPEN – opening WebSocket connection message
TEXT, BINARY – content messages
PING, PONG – ping/pong messages
CLOSE - Close message with 16-bit close code
DISCONNECT - Indicates connection closed uncleanly
1. From client to Pushpin (port 7999):
GET /chat HTTP/1.1
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: T6IDGBEmb...
Connection: Upgrade
Upgrade: websocket
2. From Pushpin to backend:
POST /chat HTTP/1.1
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-events
Accept:
application/websocket-events
OPENrn
2. Response:
HTTP/1.1 200 OK
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-events
OPENrn
WebSocket over HTTP connection flow
3. Form Pushpin to client:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBi...
Sec-WebSocket-Extensions: grip
1. From client to Pushpin (port 7999):
//sending message
WebSocket.send(“Hello there! I’m client!”);
2. From Pushpin to backend:
POST /chat HTTP/1.1
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-events
Accept:
application/websocket-events
TEXT 18rn
Hello there! I’m client!
2. Response:
HTTP/1.1 200 OK
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-events
TEXT 12rn
Hello! I’m server!
TEXT 2Frn
c:{"type": "subscribe", "channel":
"mychannel"}rn
WebSocket over HTTP message flow
3. On client:
//receiving message
WebSocket.onMesssage(event) …
//event.data is “Hello! I’m server!”
PublishSubscribe. Control messages.
Formatted as a JSON object following the c: prefix. The object has a type
field that indicates the type of control message.
● subscribe: Subscribe connection to the channel specified by the
channel field.
● unsubscribe: Unsubscribe connection from the channel specified by
the channel field.
● detach: Terminate the session between Pushpin and the origin server,
but retain the connection between the client and
http://pushpin.org/docs/#websockets
Examples:
c:{"type": "subscribe", "channel": "test"}
c:{"type": "unsubscribe", "channel": "test"}
Prefix c: is configurable
Publish data to a channel
POST request to a Pushpin’s internal publish port
(5561 by default)
curl -d
'{"items": [
{ "channel": "test",
"formats": {
"ws-message": {
"content": "hello
theren"
}
}
}
]
}' http://localhost:5561/publish/
1. From client to Pushpin:
GET /chat HTTP/1.1
Sec-WebSocket-Version: 13
Sec-WebSocket-Key:
T6IDGBEmb...
Connection: Upgrade
Upgrade: websocket
2. Request:
POST /chat HTTP/1.1
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-
events
Accept:
application/websocket-
events
OPENrn
2. Response:
HTTP/1.1 200 OK
Sec-WebSocket-Extensions: grip
Content-Type:
application/websocket-
events
OPENrn
So, all we need is to handle Requests from Pushpin
in our application. A GOOD job for Symfony, isn't it?
3. Form Pushpin to client:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBi...
Sec-WebSocket-Extensions: grip
PHP Library to work with Pushpin on server side
composer require fanout/gripcontrol
https://github.com/fanout/php-
gripcontrol
Publishing from PHP
https://github.com/fanout/php-
gripcontrol
Symfony Bundle
https://github.com/smart-gamma/pushpin-bundle
&
Features
● Works with WebSocket-over-HTTP Requests from
Pushpin
● TEXT events deserialization into DTOs (events)
specified by your configuration
● Handling WebSocketEvent with your specific
handler
● Pushpin helpers to publishing to a channel,
subscribing, detaching etc.
Live Demo&
http://ws-chat.smart-gamma.com
https://github.com/smart-gamma/simple-chat-
demo
Symfony Bundle
$ composer require gamma/pushpin-bundle
# config.yml
gamma_pushpin:
proxy:
control_uri: 'http://localhost:5561/'
web_socket:
json_events:
base_namespace: 'DomainWebsocketEvents'
mappings:
chatMessage:
class: 'ChatChatMessage'
chatRoomEnter:
class: 'ChatChatRoomEnter'
chatRoomLeave:
class: 'ChatChatRoomLeave'
&
Simple DTO object to hold event data&
Implement handler service
for your event
&
Controller to handle requests from
Pushpin
&
Test with wscat utility&
&
http://blog.fanout.io/2013/10/30/pushing-to-100000-api-clients-simultaneously/
Pros
● It’s still PHP!
● No need to run
long lived processes at backend
● With HTTP Streaming You can
make a real-time API
● Horizontally scalable
Cons
● If you have multi nodes,
pushes should be sent to all
Pushpin instances
● More HTTP requests to your
application
● Push can be sent only to a
channel
Load testing with thor utility
Thank You!

More Related Content

Real-Time Web applications with WebSockets

  • 2. About me ● WEB developer since 2009 ● Symfony developer at SmartGamma since 2013 ● https://github.com/stas-zozulja ● https://www.facebook.com/stas.zozulj a Real-Time Web applications with Websocket
  • 3. Real-Time Web applications with Websocket Agenda ● What is Real-Time Web? ● Transport mechanisms ● Real-Time in PHP (Ratchet) ● && everywhere (Pushpin)
  • 4. What is Real-Time ? https://www.leggetter.co.uk/2016/04/22/what-is-realtime.html ● Hard real-time - missed deadline? System fault ● Firm real-time - missed? Result is zero ● Soft real-time - missed? quality degrades it's all about deadline
  • 5. and Real-Time Web? Server pushes a data to Clients when some event occurs, while Clients does not need to poll a server for new data. it's all about Push https://www.leggetter.co.uk/2016/04/22/what-is-realtime.html
  • 6. Do I need real-time? YES! You do! ● Better UX - instant data updates ● Chatting, notification, signaling ● Activity streams ● Data visualization ● User collaboration
  • 7. Transport mechanisms ● Long polling ● HTTP streaming ● WebSockets
  • 8. Long polling Delayed HTTP request. After response (or timeout) new request is opening by client. ● Uni-directional ● Overhead (headers in each request)
  • 9. HTTP Streaming Request that never ends, response content is chunked in portions, usually JSON. Only one direction.
  • 10. WebSocket protocol Protocol providing bidirectional communication channel over a single TCP connection.
  • 11. WebSocket handshake Request: GET /chat HTTP/1.1 Host: ws.example.com:8080/chat Sec-WebSocket-Version: 13 Sec-WebSocket-Key: T6IDGBEmb... Connection: Upgrade Upgrade: websocket Response: HTTP/1.1 101 Switching protocols Connection: Upgrade Sec-WebSocket-Accept: xTComwY... Upgrade: websocket X-Powered-By: Ratchet/0.3.4 ws:// wss:// https://tools.ietf.org/html/rfc6455 http://caniuse.com/#feat=websockets Support: ● IE 10+ ● FF 6+ ● Chrome 14+ ● iOS 4.2+ ● Android 4.4+ ● Safari 5+
  • 12. Our context ● Live streaming app ● REST API for mobile clients (iOS, Android) ● WEB part ● Build Real-time counter of viewers or
  • 13. Ratchet - WebSockets for PHP http://socketo.me/ Built on top of ReactPHP Components: ● I/O (socket transport) – IOServer ● HTTP Protocol handler – HTTPServer ● WebSocket Protocol Handler – WSServer ● SessionProvider – Symfony Session ● WAMP Protocol Handler – WampServer + ● Your Application MessageComponentInterface implementation http://reactphp.org/
  • 14. & Step 1. Implement MessageComponentInterface
  • 15. & Step 2. onMessage()
  • 16. & Step 3. Write Console command that runs a server
  • 17. & Next steps. WAMP Subprotocol. ● WAMP – Web Application Messaging Protocol. ● RPC and Pub/Sub patterns ● Autobahn client libraries http://wamp-proto.org/ http://autobahn.ws/
  • 18. & Cons ● Horizontally scaling is hard need to share a Connections between nodes ● One exception can stop whole server Use supervisord, try...catch, test Your code Pros ● Its PHP! ● Easy to implement and use existing code
  • 21. Pushpin a reverse proxy for the real-time Web http://pushpin.org/ ● Pub/Sub ● Long polling, HTTP Streaming or WebSockets ● Works with any backend ● Your API can be real-time with HTTP streaming ● WebSocket over HTTP – what? :) https://fanout.io/
  • 22. Pushpin installation Debian, Ubuntu: sudo apt-get install pushpin sudo service pushpin start http://pushpin.org/docs/#install MacOS X: brew install pushpin pushpin
  • 23. Pushpin configuration routes config file: * localhost:80,over_http ● route all connections from Pushpin to your backend ● over_http option to enable WebSocket-over-HTTP protocol https://github.com/fanout/pushpin/wiki https://github.com/fanout/pushpin/blob/master/docs/websocket-over-http.md
  • 24. WebSocket-over-HTTP (GRIP protocol) Pushpin encodes WebSocket events into a regular HTTP requests and passes them to your backend. Events are: OPEN – opening WebSocket connection message TEXT, BINARY – content messages PING, PONG – ping/pong messages CLOSE - Close message with 16-bit close code DISCONNECT - Indicates connection closed uncleanly
  • 25. 1. From client to Pushpin (port 7999): GET /chat HTTP/1.1 Sec-WebSocket-Version: 13 Sec-WebSocket-Key: T6IDGBEmb... Connection: Upgrade Upgrade: websocket 2. From Pushpin to backend: POST /chat HTTP/1.1 Sec-WebSocket-Extensions: grip Content-Type: application/websocket-events Accept: application/websocket-events OPENrn 2. Response: HTTP/1.1 200 OK Sec-WebSocket-Extensions: grip Content-Type: application/websocket-events OPENrn WebSocket over HTTP connection flow 3. Form Pushpin to client: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBi... Sec-WebSocket-Extensions: grip
  • 26. 1. From client to Pushpin (port 7999): //sending message WebSocket.send(“Hello there! I’m client!”); 2. From Pushpin to backend: POST /chat HTTP/1.1 Sec-WebSocket-Extensions: grip Content-Type: application/websocket-events Accept: application/websocket-events TEXT 18rn Hello there! I’m client! 2. Response: HTTP/1.1 200 OK Sec-WebSocket-Extensions: grip Content-Type: application/websocket-events TEXT 12rn Hello! I’m server! TEXT 2Frn c:{"type": "subscribe", "channel": "mychannel"}rn WebSocket over HTTP message flow 3. On client: //receiving message WebSocket.onMesssage(event) … //event.data is “Hello! I’m server!”
  • 27. PublishSubscribe. Control messages. Formatted as a JSON object following the c: prefix. The object has a type field that indicates the type of control message. ● subscribe: Subscribe connection to the channel specified by the channel field. ● unsubscribe: Unsubscribe connection from the channel specified by the channel field. ● detach: Terminate the session between Pushpin and the origin server, but retain the connection between the client and http://pushpin.org/docs/#websockets Examples: c:{"type": "subscribe", "channel": "test"} c:{"type": "unsubscribe", "channel": "test"} Prefix c: is configurable
  • 28. Publish data to a channel POST request to a Pushpin’s internal publish port (5561 by default) curl -d '{"items": [ { "channel": "test", "formats": { "ws-message": { "content": "hello theren" } } } ] }' http://localhost:5561/publish/
  • 29. 1. From client to Pushpin: GET /chat HTTP/1.1 Sec-WebSocket-Version: 13 Sec-WebSocket-Key: T6IDGBEmb... Connection: Upgrade Upgrade: websocket 2. Request: POST /chat HTTP/1.1 Sec-WebSocket-Extensions: grip Content-Type: application/websocket- events Accept: application/websocket- events OPENrn 2. Response: HTTP/1.1 200 OK Sec-WebSocket-Extensions: grip Content-Type: application/websocket- events OPENrn So, all we need is to handle Requests from Pushpin in our application. A GOOD job for Symfony, isn't it? 3. Form Pushpin to client: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBi... Sec-WebSocket-Extensions: grip
  • 30. PHP Library to work with Pushpin on server side composer require fanout/gripcontrol https://github.com/fanout/php- gripcontrol
  • 32. Symfony Bundle https://github.com/smart-gamma/pushpin-bundle & Features ● Works with WebSocket-over-HTTP Requests from Pushpin ● TEXT events deserialization into DTOs (events) specified by your configuration ● Handling WebSocketEvent with your specific handler ● Pushpin helpers to publishing to a channel, subscribing, detaching etc.
  • 34. Symfony Bundle $ composer require gamma/pushpin-bundle # config.yml gamma_pushpin: proxy: control_uri: 'http://localhost:5561/' web_socket: json_events: base_namespace: 'DomainWebsocketEvents' mappings: chatMessage: class: 'ChatChatMessage' chatRoomEnter: class: 'ChatChatRoomEnter' chatRoomLeave: class: 'ChatChatRoomLeave' &
  • 35. Simple DTO object to hold event data&
  • 37. Controller to handle requests from Pushpin &
  • 38. Test with wscat utility&
  • 39. & http://blog.fanout.io/2013/10/30/pushing-to-100000-api-clients-simultaneously/ Pros ● It’s still PHP! ● No need to run long lived processes at backend ● With HTTP Streaming You can make a real-time API ● Horizontally scalable Cons ● If you have multi nodes, pushes should be sent to all Pushpin instances ● More HTTP requests to your application ● Push can be sent only to a channel
  • 40. Load testing with thor utility