WebSocket For Web Rubyists
-
Upload
mu-fan-teng -
Category
Technology
-
view
5.293 -
download
1
Transcript of WebSocket For Web Rubyists
自己紹介鄧 慕凡(テン ムファン)
a.k.a: 竜堂 終
両方どもある小説の登場人物
Github / Twitter: @ryudoawaru
http://ryudo.tw
Websocket
W3C / HTML5 Standard
Standard Javascript API
Full-duplex
Pub-Sub between client and server
EM-Websocket
From 2009
Simple implementation
Easily handle c10k by 1 process
http://shokai.org/blog/archives/7149
Typical Server Side Code
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws| ws.onopen { ws.send "Hello Client!"} ws.onmessage { |msg| ws.send "Pong: #{msg}" } ws.onclose { puts "WebSocket closed" } end
Typical Client Side Code
var ws = new WebSocket('ws://host/uri'); ws.onopen = function() { show('websocket opened'); }; ws.onclose = function() { show('websocket closed'); } ws.onmessage = function(m) { show('websocket message: ' + m.data); }; ws.send('Hello Websocket!!');
How does it workClient Server
Handshake Response
Websocket
Handshake Request
GET /chat HTTP 1.1 Host: server.host.com Upgrade: Websocket Connection: Upgrade Origin: http://host.com Sec-Websocket-Key: “WwV7thr/Uwrg3mA57risrQ==" Sec-WebSocket-Version:"13"
Connection:”Upgrade" Sec-WebSocket-Accept: F0VaFFGV/JHx1hJWBlhuJAqdse8= Upgrade:"websocket"
Events
onopen:When new connection is established
onmessage:When new message comes from another side
onclose:When connection is closed by the other side
Message Flow
Server
Client
Client
Client
1. send msg
2. onmessage
3. Send to all clients
4. onmessage
Basic EM-WebSocket Code Style
conns_in_channel = Set.new EM::WebSocket.start(...) do |ws| ws.onopen do |request| conns_in_channel.add ws end ws.onmessage do |msg| conns_in_channel.each do |conn| EM.next_tick{conn.send(msg)} end end ws.onclose do conns_in_channel.delete ws end end
Store connection
Remove connection on quit
Set to store connection
Send msg to connections 1 by 1
Live with HTTP Service in the Rack Stack
request.websocket?
Rack Stack
WebSocketOther Rack Stuffs
YES NO
Identify by Request Headers
# middlewares/chat_backend.rb def call(env) if Faye::WebSocket.websocket?(env) # WebSockets logic goes here ws.rack_response else @app.call(env) end end
https://devcenter.heroku.com/articles/ruby-websockets
Identify by Request Headers
# config/routes.rb Example::Application.routes.draw do match "/websocket", :to => ActionCable.server, via: [:get, :post] end
https://github.com/rails/actioncable
Normal Web Services
Keeps Connection for very short period.
Process could be terminated w/o affecting any client.
Client Server
open
close
open
close
WebSocket Service
Long-running Connection
Stop process means killing all connections.
Server
Client
Client
Client
Concurrency Model
WebSocket Gems use one of following concurrency models:
Reactor: EventMachine based Gems.
Thread: Tubesock.
Mixed: ActionCable
This may conflicts with model of your normal Web Services.
Comparison of Connection Features
Normal Web Works WebSocket
Connection Period short long
Concurrency Model Depend on App Server Reactor or Thread
Process Long-Running? No Yes
Authentication Issue
Client Server
Handshake Request
Handshake Response
Websocket
Confirm at this point!
Identify by Cookie
Easy approach for web developers.
WebSocket may run at different host.
Some browsers don’t support cookie on ws:// request.
Most mobile APP’s http client may not support cookie/session by default.
Identify by URL
Client
⓵GET http://host/chat
WebSocketWeb Service
⓷Use ticket to handshake
⓸Identity confirmed
⓶Generate URL: ws://host2/abc1234 as “ticket”
Attention
Security issue:
The “ticket" should be removed from database after connection established.
Should only be valid in a short time.
http://www.focus-sport.club.tw/
Serve all platforms by one stack.
Runs Permanently.
Handle more than 1k concurrent connections very easily.