Ruby EventMachine: a short introduction
Introduction
Before answering what is EventMachine, first I will try to explain the problem that EventMachine solves.
A network server like http server or chat server usually works in a threaded model. What it means is that on a particular port, a process is listening for connections. When a client makes a connection then this process spawns a new thread and that thread is handed over the task of responding to that client. If server is getting too much traffic then the number of threads created by the main process goes up very quickly.
The job of newly created thread is to service client request. And while this thread is servicing the request of client, it can’t do anything else even if it means waiting for other stuff. What are the other stuff a thread might wait for. Well I/O operations are usually slow. A thread might be waiting for I/O operation. Or it might be connecting to an external resource and the handshake might be taking a while. Or connecting to a database etc. The point is that threads can’t do anything else while they are waiting on other resource. Such a waste!
This process of creating a new thread to handle a new client can be called ‘threaded framework’. An alternative is ‘event driven framework’. In a ‘event driven network’ calls are non-blocking. What it means is that the server will react to events. Let me show you a simple case.
temp = make_a_webservice_call_to_weather_dot_com_to_get_temperature puts temp c = 50 d = 20 puts c - d
In an ‘threaded framework’ when thread comes across the line of code where a web service call is made, thread will pause and will not move on until a response has come from web service. In a ‘event driven framework’, thread will make a web service call. It will make note of the handlers and it will move on to next instruction. In this case rather than waiting for the response from weather site to come, thread will start executing next set of instructions. And it is quite possible that it will get the result of 50 – 20 to the user before it receives a response from weather site. When the thread does get a response from weather site then it will do whatever it has been instructed to do.
If you have done any AJAX programming then you will understand what I am talking about. Event driven frameworks work exactly like asynchronous calls.
Event driven tools
There are some tools available in the market which operate on event driven model. The newest one is node.js . I would encourage you to watch this video presentation by the creator of node.js which was presented at The European JavaScript Conference 2009 .
Thin web server is built on event driven framework.
Twisted is an event driven networking engine built in Python.
EventMachine is and event driven engine written in ruby. In many ways it is similar to Twisted .
EventMachine
EventMachine is a ruby implementation of event driven framework. It separates the networking logic and business logic. It allows consumers to concentrate on business logic and it takes care of all the issues related to sockets and networking layer. Because event driven frameworks are not tied to a single request, they usually have very good performance.
How to install EventMachine
sudo gem install eventmachine
You need c++ compiler to build native extensions.
EventMachine as simple echo server
Below is code for a simple echo server. Save this file as server.rb
require 'rubygems'
require 'eventmachine'
module EchoServer
def receive_data(data)
send_data "server received: #{data}"
close_connection if data =~ /quit|exit/i
end
end
EventMachine::run {
EventMachine::start_server "127.0.0.1", 6789, EchoServer
}
Start the server.
ruby server.rb
telent into the server and issue some commands.
> telnet 127.0.0.1 6789 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello World server received: Hello World EventMachine rocks server received: EventMachine rocks quit Connection closed by foreign host.
I will discuss step by step instructions in later section.
EventMachine as a client
EventMachine can also act as client.
require 'rubygems'
require 'eventmachine'
module Client
def post_init
send_data "GET /\r\n\r\n"
end
def receive_data(data)
puts data
end
end
EventMachine::run do
EventMachine::connect 'www.rubyonrails.org', 80, Client
end
Running the code brings this result.
> ruby client.rb <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">Index of / Index of /
| Name | Last modified | Size | Description | |
|---|---|---|---|---|
How EventMachine really works
In this section I am going to discuss the callback mechanism of EventMachine. I’m going to start with a sever. Here is code for server.
require 'rubygems'
require 'eventmachine'
module EchoServer
def post_init
puts "-- someone connected to the echo server!"
end
def receive_data data
send_data ">>>you sent: #{data}"
close_connection if data =~ /quit/i
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
EventMachine::run {
EventMachine::start_server "127.0.0.1", 6789, EchoServer
}
As you can see, I am asking EventMachine to start a server at 127.0.0.1 listening on port 6789. When I start the server then EventMachine starts running and it will run forever until I kill it. Now that EventMachine is running, it is able to accept client connections.
The third and the final argument while starting the server was a module ( EchoServer in this case ). When a client connects to server then EventMachine creates an anonymous class. EventMachine mixes in the module supplied (EchoServer) in that class. The anonymous class that EventMachine created is on the server side. Client is not even aware of it. As far as server is concerned client might or might not be a ruby application. The key thing is that when that client makes a second request then EventMachine will bring up the same anonymous class that it used in the first case. It means that the state stored in the anonymous class during the first request will be available to the client during the second request. If you do not get all this on your first read then don’t worry about it. It took me forever to understand this simple concept that EventMachine will bring up the same anonymous class and hence the state is preserved.
When a client makes the connection to a EventMachine server then post_init method is called. This method is invoked only once when client connect to sever. After connecting to server, if client sends a message then method receive_data is invoked. The server can send data back to client by calling method send_data . When client terminates the connection then method unbind is called.
Note that when client closes the connection then it means that client is not connected to server anymore. The server is still running and listening on the specified port.
Recap: The module that is passed to the server (EchoServer) is the module that is mixed into an anonymous class. Exactly one anonymous class is created per connected client. If a client closes the connection and if it reconnects then that client is going to get a new anonymous class and all previously saved state is gone.
Let’s say that I have two clients: client1 and client2 connected to an EventMachine server. if client1 sends a message to server and if server’s receive_data is defined as
def receive_data data
send_data ">>>you sent: #{data}"
end
then only the client that sent the message is going to get the echo back. It goes like this
client1 connects to server client2 connects to server client1 sends a message to server client2 sends a message to server server sends the echo back to client1 server sends the echo back to client2
EventMachine comes into discussion a lot with chat server and some assume that the reply sent by server is a broadcast to all connected clients. That is not true. Each send_data call sends message to a client. If you want to send message to all connected clients then you will have to do that yourself.
When clients connect to server then server can store that list of clients connected and when times comes to broadcast the message then messages can be sent to each of the clients like this.
require 'rubygems'
require 'eventmachine'
module EchoServer
def post_init
$clients_list ||= {}
@identifier = self.object_id
$clients_list.merge!({@identifier => self})
end
def receive_data data
# broadcast this message to all clients
$clients_list.values.each do |client|
client.send_data(data)
end
end
def unbind
$clients_list.delete(@identifier)
end
end
EventMachine::run {
EventMachine::start_server "127.0.0.1", 6789, EchoServer
}
In the above case a chat message is being broadcasted to all the connected clients.
TCP Connection
If you are writing a chat application and the controller needs to connect to an instance of EventMachine server then this is how it can be done.
socket = TCPSocket.open(ip_address, port)
data = {:client_id => 'ibm', :message => 'hello world'}
socket.send(data)
response = socket.gets
socket.close
There are a lot more articles on EventMachine. Just google for them. Here is one article which describes how fast EventMachine could be compared to a ‘threaded framework’.
- Add new comment
- 180 reads
- Feed: neeraj.name
- Original article





Recent comments
1 week 1 day ago
1 week 2 days ago
3 weeks 1 day ago
5 weeks 3 days ago
20 weeks 1 day ago
23 weeks 1 day ago
23 weeks 6 days ago
23 weeks 6 days ago
24 weeks 1 day ago
26 weeks 3 days ago