Skip to content
This repository has been archived by the owner on Dec 7, 2018. It is now read-only.

Basic Usage

Mikhail Chuprysnki edited this page Feb 1, 2016 · 10 revisions

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 core TCPServer and TCPSocket classes which automatically use an evented mode inside of Celluloid::IO actors. They're named Celluloid::IO::TCPServer and Celluloid::IO::TCPSocket, so they're automatically available inside your class when you include Celluloid::IO.

  • Asynchronous method calls: You may have noticed that while the methods of EchoServer are named run and handle_connection, they're invoked as async.run and async.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 of Celluloid::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.

Clone this wiki locally