EventMachine + WebSockets, #rorosyd talk
January 11 2012, 3:02 PM by David Parry
EventMachine + WebSockets
This is the notes from a talk I gave at #rorosyd on the 10th of January 2012.
The demo code is available at: [https://github.com/suranyami/socket_demo][]
So, what’s EventMachine?
- Reactor pattern
- Extremely high performance
- Doesn’t need threads, concurrency
- Addresses the C10K problem
- Callbacks
- Fast, low memory overhead
EventMachine supports lots of protocols!
There is a great list of currently implemented protocols at https://github.com/eventmachine/eventmachine/wiki/Protocol-Implementations which includes:
- HeaderAndContent
- SMTPServer
- Stomp
- Socks4
- ObjectProtocol
- SASLauth
- LineAndText
- LineText2
- HTTPClient
- HTTPClient2
- AMQP
- MySQL
- SMTP
- Postgres
- MemCache
- XMPP
- DNS
- PowerDNS
- ICMP
- XML Push Parser
- Redis
- MongoDB
- CouchDB
- Beanstalk
- SNMP
- HTTPRequest
- HTTPServer
- PubSubHubbub
- Proxy
- WebSocket
- SMPP
- RPC
- IRC
- Spec
- Cassandra
- Thrift
- Solr
- Syslog
- Amazon S3
- OSCAR (AIM, ICQ)
- RServe
- SSH
How to learn about EventMachine?
Example of a Trivial Telnet Server
require 'eventmachine'
class Echo < EM::Connection
def receive_data(data)
send_data(data)
end
end
EM.run do
EM.start_server(“0.0.0.0”, 10000, Echo)
end
So, what’s a WebSocket?
- Used for “push”, real-time bidirectional updates
- HTML 5, proposed RFC, too.
- In all modern browsers Chrome Safari, Safari Mobile Firefoxx but NOT Android browser (FFS! Why?) ** IE 10, but not IE 6-9 (who cares!)
- iOS native library + elsewhere
- Combining EventMachine + WebSocket = em-websocket
Where would I use it?
- Chat
- Multiplayer Games
- Real-time dataviz
- Real-time news feeds
- Real-time anything
Trivial WebSocket server
require 'eventmachine'
require 'em-websocket'
conf = {:host => “0.0.0.0”, :port => 8080}
EM.run {
EventMachine::WebSocket.start(conf) do |ws|
ws.onopen {ws.send "Hello Client"}
ws.onclose { puts "Connection closed" }
ws.onmessage {|msg| ws.send "Echo: #{msg}"}
end }
A Less Trivial example
So, I wanted something to demo that wasn’t trying to do to much but demonstrated the real-time nature of WebSockets, so I built this little socket_demo site:
- Sinatra serves HTML, JS (CoffeeScript), CSS
- Running an EM-WebSocket server
- Each guest decides whether a block is green or red (default’s white)
- Joining/leaving adds/removes blocks
- New guest gets snapshot of world
Useless, but non-trivial!
CoffeeScript
Assign an id to socket/guest
EM-Websocket Server:
class Demo constructor: –>
if WebSocket?
window.socket = new WebSocket("ws://192.168.1.3:7070")
else
window.socket = new MozWebSocket("ws://192.168.1.3:7070")
Register ourselves
CoffeeScript:
window.socket.onopen = –>
window.socket.send JSON.stringify({kind: “register”})
EM-Websocket Server:
socket.onmessage do |msg|
puts "Server Received #{msg}"
id = @sockets[socket][“id”]
incoming = ActiveSupport::JSON.decode(msg)
case incoming[“kind”]
when "register"
socket.send(register_message(id).to_json)
broadcast(id)
else
## Send “add” event to everyone
EM-Websocket Server:
def send_to_all(message) @sockets.each do |destination|`
destination.send(message.to_json)
end
CoffeeScript:
```coffeescript
window.socket.onmessage = (mess) –>
data = jQuery.parseJSON(mess.data)
switch data[“kind”]
when "add"
window.add_player data["id"], data["color"]
Send click events
$(“#red”).click (e) => window.socket.send JSON.stringify {kind: “update”, color: “red”}
$(“#green”).click (e) => window.socket.send JSON.stringify {kind: “update”, color: “green”}
Server gets a message
socket.onmessage do |msg|
id = @sockets[socket][“id”] incoming = ActiveSupport::JSON.decode(msg)
case incoming[“kind”]
when “register”
socket.send(register_message(id).to_json)
broadcast(id)
else
if incoming["color"]
color = incoming["color"]
message = {"kind" => "update", "id" => id, "color" => color}
@sockets[socket]["color"] = color
send_to_all(message)
end
end
end
Live Demo
Then I gave a live demo where I used my laptop as an unsecured base station, and people connected to it with their iPhones and started clicking on the red/green buttons:
wifi: suranyami (no password) url: test.local:4567
How to do testing with EventMachine?
em-spec https://github.com/joshbuddy/em-spec
This demo code viewable here: [https://github.com/suranyami/socket_demo][]
September 11th, 2013 2:19pm