README.md in celluloid-io-0.8.0 vs README.md in celluloid-io-0.9.0

- old
+ new

@@ -1,82 +1,156 @@ -Celluloid::IO +![Celluloid](https://github.com/tarcieri/celluloid-io/raw/master/logo.png) ============= -[![Build Status](http://travis-ci.org/tarcieri/celluloid-io.png)](http://travis-ci.org/tarcieri/celluloid-io) +[![Build Status](https://secure.travis-ci.org/tarcieri/celluloid-io.png?branch=master)](http://travis-ci.org/tarcieri/celluloid-io) +[![Dependency Status](https://gemnasium.com/tarcieri/celluloid-io.png)](https://gemnasium.com/tarcieri/celluloid-io) -You don't have to choose between threaded and evented IO! Celluloid::IO provides -a simple and easy way to wait for IO events inside of a Celluloid actor, which -runs in its own thread. Any Ruby IO object can be registered and monitored. -It's a somewhat similar idea to Ruby event frameworks like EventMachine and -Cool.io, but Celluloid actors automatically wrap up all IO in Fibers, -resulting in a synchronous API that's duck type compatible with existing IO -objects. +You don't have to choose between threaded and evented IO! Celluloid::IO +provides an event-driven IO system for building fast, scalable network +applications that integrates directly with the +[Celluloid actor library](https://github.com/tarcieri/celluloid), making it +easy to combine both threaded and evented concepts. Celluloid::IO is ideal for +servers which handle large numbers of mostly-idle connections, such as Websocket +servers or chat/messaging systems. -Unlike EventMachine, you can make as many Celluloid::IO actors as you wish, -each running their own event loop independently from the others. Using many -actors allows your program to scale across multiple CPU cores on Ruby -implementations which don't have a GIL, such as JRuby and Rubinius. +Celluloid::IO provides a different class of actor: one that's slightly slower +and heavier than standard Celluloid actors, but one which contains a +high-performance reactor just like EventMachine or Cool.io. This means +Celluloid::IO actors have the power of both Celluloid actors and evented +I/O loops. Unlike certain other evented I/O systems which limit you to a +single event loop per process, Celluloid::IO lets you make as many actors as +you want, system resources permitting. +Rather than callbacks, Celluloid::IO exposes a synchronous API built on duck +types of Ruby's own IO classes, such as TCPServer and TCPSocket. These classes +work identically to their core Ruby counterparts, but in the scope of +Celluloid::IO actors provide "evented" performance. Since they're drop-in +replacements for the standard classes, there's no need to rewrite every +library just to take advantage of Celluloid::IO's event loop and you can +freely switch between evented and blocking IO even over the lifetime of a +single connection. + +Celluloid::IO uses the [nio4r gem](https://github.com/tarcieri/nio4r) +to monitor IO objects, which provides cross-platform and cross-Ruby +implementation access to high-performance system calls such as epoll +and kqueue. + Like Celluloid::IO? [Join the Google Group](http://groups.google.com/group/celluloid-ruby) Supported Platforms ------------------- -Celluloid works on Ruby 1.9.2+, JRuby 1.6 (in 1.9 mode), and Rubinius 2.0. JRuby -or Rubinius are the preferred platforms as they support true hardware-level -parallelism when running Ruby code, whereas MRI/YARV is constrained by a global -interpreter lock (GIL). +Celluloid::IO works on Ruby 1.9.2+, JRuby 1.6 (in 1.9 mode), and Rubinius 2.0. To use JRuby in 1.9 mode, you'll need to pass the "--1.9" command line option to the JRuby executable, or set the "JRUBY_OPTS=--1.9" environment variable. -Celluloid works on Rubinius in either 1.8 or 1.9 mode. - Usage ----- -To use Celluloid::IO, define a normal Ruby class that includes Celluloid::IO: +To use Celluloid::IO, define a normal Ruby class that includes Celluloid::IO. +The following is an example of an echo server: ```ruby require 'celluloid/io' -class MyServer +class EchoServer include Celluloid::IO - # Bind a TCP server to the given host and port def initialize(host, port) - @server = TCPServer.new 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) run! end - # Run the TCP server event loop - def run - while true - wait_readable(@server) - on_connect @server.accept - end + def finalize + @server.close if @server end - # Terminate this server - def terminate - @server.close - super + def run + loop { handle_connection! @server.accept } end - # Called whenever a new connection is opened - def on_connect(connection) - connection.close + 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" 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](https://github.com/tarcieri/celluloid/). +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 + *run!* and *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](https://github.com/tarcieri/celluloid-io/blob/master/lib/celluloid/io/reactor.rb). + 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. + +The result is an API for doing evented I/O that looks identical to doing +synchronous I/O. Adapting existing synchronous libraries to using evented I/O +is as simple as having them use one of Celluloid::IO's provided replacement +classes instead of the core Ruby TCPSocket and TCPServer classes. + +Status +------ + +The rudiments of TCPServer and TCPSocket are in place and ready to use. +Several methods are still missing. Making new connections with +Celluloid::IO::TCPSocket.new works, however it presently does blocking DNS +resolution and connect so it can stall the reactor loop. + +Basic UDPSocket support is in place. On JRuby, recvfrom makes a blocking call +as the underlying recvfrom_nonblock call is not supported by JRuby. + +No UNIXSocket support yet, sorry (patches welcome!) + Contributing to Celluloid::IO ----------------------------- -* Fork Celluloid on github +* Fork this repository on github * Make your changes and send me a pull request -* If I like them I'll merge them and give you commit access to my repository +* If I like them I'll merge them +* If I've accepted a patch, feel free to ask for a commit bit! License ------- Copyright (c) 2011 Tony Arcieri. Distributed under the MIT License. See LICENSE.txt for further details. + +Contains code originally from the RubySpec project also under the MIT License +Copyright (c) 2008 Engine Yard, Inc. All rights reserved.