-
Notifications
You must be signed in to change notification settings - Fork 93
Basic Usage
To use Celluloid::IO
, define a normal Ruby class that includes Celluloid::IO
.
The following is an example of an echo server:
require 'celluloid/current'
require 'celluloid/io'
class EchoServer
include Celluloid::IO
finalizer :shutdown
def initialize(host, port)
puts "*** Starting echo server on #{host}:#{port}"
# Since we included Celluloid::IO, we're actually making a
# Celluloid::IO::TCPServer here
@server = TCPServer.new(host, port)
async.run
end
def shutdown
@server.close if @server
end
def run
loop { async.handle_connection @server.accept }
end
def handle_connection(socket)
_, port, host = socket.peeraddr
puts "*** Received connection from #{host}:#{port}"
loop { socket.write socket.readpartial(4096) }
rescue EOFError
puts "*** #{host}:#{port} disconnected"
socket.close
end
end
The very first thing including Celluloid::IO
does is also include the
Celluloid
module, which promotes objects of this class to concurrent Celluloid
actors each running in their own thread. Before trying to use Celluloid::IO
you may want to familiarize yourself with Celluloid
in general.
Celluloid
actors can each be thought of as being event loops. Celluloid::IO
actors
are heavier but have capabilities similar to other event loop-driven frameworks.
While this looks like a normal Ruby TCP server, there aren't any threads, so you might expect this server can only handle one connection at a time. However, this is all you need to do to build servers that handle as many connections as you want, and it happens all within a single thread.
The magic in this server which allows it to handle multiple connections comes in three forms:
-
Replacement classes:
Celluloid::IO
includes replacements for the coreTCPServer
andTCPSocket
classes which automatically use an evented mode inside ofCelluloid::IO
actors. They're namedCelluloid::IO::TCPServer
andCelluloid::IO::TCPSocket
, so they're automatically available inside your class when you includeCelluloid::IO
. -
Asynchronous method calls: You may have noticed that while the methods of
EchoServer
are namedrun
andhandle_connection
, they're invoked asasync.run
andasync.handle_connection
. This queues these methods to be executed after the current method is complete. You can queue up as many methods as you want, allowing asynchronous operation similar to the "call later" or "next tick" feature of Twisted, EventMachine, and Node. This echo server first kicks off a background task for accepting connections on the server socket, then kicks off a background task for each connection. -
Reactor + Fibers:
Celluloid::IO
is a combination of Actor and Reactor concepts. The blocking mechanism used by the mailboxes ofCelluloid::IO
actors is an nio4r-powered reactor. When the current task needs to make a blocking I/O call, it first makes a non-blocking attempt, and if the socket isn't ready the current task is suspended until the reactor detects the operation is ready and resumes the suspended task.