1
0
mirror of https://github.com/bitwarden/help synced 2025-12-27 21:53:15 +00:00

Promote to Master (#748)

* initial commit

* adding quotes for the array error

* Create Gemfile

* Create Gemfile.lock

* add .nvmrc and .node-version

* removed /article from URL

* update links to work with netlify

* more fixed links

* link fixes

* update bad links

* Update netlify.toml

toml test for redirects

* article redirect

* link fixes

* Update index.html

* Update netlify.toml

* Update _config.yml

* Update netlify.toml

* Update netlify.toml

* Update netlify.toml

* Update netlify.toml

* Update netlify.toml

* add article back into URL for launch

* Update netlify.toml

* Update netlify.toml

* add order to categories front matter

* Update netlify.toml

* update

* sidemenu update

* Revert "sidemenu update"

This reverts commit 5441c3d35c.

* update order prop

* Navbar updates per Gary and compiler warnings

* font/style tweaks

* Update sidebar.html

* Stage Release Documentation (#739)

* initial drafts

* rewrite Custom Fields article to prioritize new context-menu option & better organize ancillary information

* edit

* edit

* Custom Field Context Menu & CAPTCHA item in release notes

* SSO relink event

* update rn

* small edits

* improve release notes titles

* fix side menu

* Edits courtest of mportune!

* update order

* link fixes

* link cleanup

* image updates and a link

* fix trailing slash

Co-authored-by: DanHillesheim <79476558+DanHillesheim@users.noreply.github.com>
This commit is contained in:
fred_the_tech_writer
2021-09-21 13:21:11 -04:00
committed by GitHub
parent 63f78e8979
commit 906e2ca0dd
3304 changed files with 386714 additions and 8864 deletions

View File

@@ -0,0 +1,27 @@
# EventMachine documentation guides #
Welcome to the documentation guides for [EventMachine](http://github.com/eventmachine/eventmachine),
a fast and simple event-processing library for Ruby programs (à la JBoss Netty, Twisted, Node.js
and so on).
## Guide list ##
* {file:docs/GettingStarted.md Getting started with EventMachine}
* {file:docs/EventDrivenServers.md Writing event-driven servers}
* {file:docs/EventDrivenClients.md Writing event-driven clients}
* {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery}
* {file:docs/TLS.md TLS (aka SSL)}
* {file:docs/Ecosystem.md EventMachine ecosystem}: Thin, Goliath, em-http-request, em-websockets, Proxymachine and beyond
* {file:docs/BlockingEventLoop.md On blocking the event loop: why it is harmful for performance and how to avoid it}
* {file:docs/LightweightConcurrency.md Lightweight concurrency with EventMachine}
* {file:docs/Deferrables.md Deferrables}
* {file:docs/ModernKernelInputOutputAPIs.md Brief introduction to epoll, kqueue, select}
* {file:docs/WorkingWithOtherIOSources.md Working with other IO sources such as the keyboard}
## Tell us what you think! ##
Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3)
or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered?
Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is
key to making documentation better.

View File

@@ -0,0 +1,521 @@
# @title Getting Started with Ruby EventMachine
# @markup markdown
# @author Michael S. Klishin, Dan Sinclair
# Getting started with Ruby EventMachine #
## About this guide ##
This guide is a quick tutorial that helps you to get started with EventMachine for writing event-driven
servers, clients and using it as a lightweight concurrency library.
It should take about 20 minutes to read and study the provided code examples. This guide covers
* Installing EventMachine via [Rubygems](http://rubygems.org) and [Bundler](http://gembundler.com).
* Building an Echo server, the "Hello, world"-like code example of network servers.
* Building a simple chat, both server and client.
* Building a very small asynchronous Websockets client.
## Covered versions ##
This guide covers EventMachine v0.12.10 and 1.0 (including betas).
## Level ##
This guide assumes you are comfortable (but not necessary a guru) with the command line. On Microsoft Windows™,
we recommend you to use [JRuby](http://jruby.org) when running these examples.
## Installing EventMachine ##
### Make sure you have Ruby installed ###
This guide assumes you have one of the supported Ruby implementations installed:
* Ruby 1.8.7
* Ruby 1.9.2
* [JRuby](http://jruby.org) (we recommend 1.6)
* [Rubinius](http://rubini.us) 1.2 or higher
* [Ruby Enterprise Edition](http://www.rubyenterpriseedition.com)
EventMachine works on Microsoft Windows™.
### With Rubygems ###
To install the EventMachine gem do
gem install eventmachine
### With Bundler ###
gem "eventmachine"
### Verifying your installation ###
Lets verify your installation with this quick IRB session:
irb -rubygems
ruby-1.9.2-p180 :001 > require "eventmachine"
=> true
ruby-1.9.2-p180 :002 > EventMachine::VERSION
=> "1.0.0.beta.3"
## An Echo Server Example ##
Lets begin with the classic "Hello, world"-like example, an echo server. The echo server responds clients with the
same data that was provided. First, here's the code:
{include:file:examples/guides/getting\_started/01\_eventmachine\_echo_server.rb}
When run, the server binds to port 10000. We can connect using Telnet and verify it's working:
telnet localhost 10000
On my machine the output looks like:
~ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Let's send something to our server. Type in "Hello, EventMachine" and hit Enter. The server will respond with
the same string:
~ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, EventMachine
# (here we hit Enter)
Hello, EventMachine
# (this ^^^ is our echo server reply)
It works! Congratulations, you now can tell your Node.js-loving friends that you "have done some event-driven programming, too".
Oh, and to stop Telnet, hit Control + Shift + ] and then Control + C.
Lets walk this example line by line and see what's going on. These lines
require 'rubygems' # or use Bundler.setup
require 'eventmachine'
probably look familiar: you use [RubyGems](http://rubygems.org) (or [Bundler](http://gembundler.com/)) for dependencies and then require EventMachine gem. Boring.
Next:
class EchoServer < EventMachine::Connection
def receive_data(data)
send_data(data)
end
end
Is the implementation of our echo server. We define a class that inherits from {EventMachine::Connection}
and a handler (aka callback) for one event: when we receive data from a client.
EventMachine handles the connection setup, receiving data and passing it to our handler, {EventMachine::Connection#receive_data}.
Then we implement our protocol logic, which in the case of Echo is pretty trivial: we send back whatever we receive.
To do so, we're using {EventMachine::Connection#send_data}.
Lets modify the example to recognize `exit` command:
{include:file:examples/guides/getting\_started/02\_eventmachine\_echo_server\_that\_recognizes\_exit\_command.rb}
Our `receive\_data` changed slightly and now looks like this:
def receive_data(data)
if data.strip =~ /exit$/i
EventMachine.stop_event_loop
else
send_data(data)
end
end
Because incoming data has trailing newline character, we strip it off before matching it against a simple regular
expression. If the data ends in `exit`, we stop EventMachine event loop with {EventMachine.stop_event_loop}. This unblocks
main thread and it finishes execution, and our little program exits as the result.
To summarize this first example:
* Subclass {EventMachine::Connection} and override {EventMachine::Connection#send_data} to handle incoming data.
* Use {EventMachine.run} to start EventMachine event loop and then bind echo server with {EventMachine.start_server}.
* To stop the event loop, use {EventMachine.stop_event_loop} (aliased as {EventMachine.stop})
Lets move on to a slightly more sophisticated example that will introduce several more features and methods
EventMachine has to offer.
## A Simple Chat Server Example ##
Next we will write a simple chat. Initially clients will still use telnet to connect, but then we will add little
client application that will serve as a proxy between telnet and the chat server. This example is certainly longer
(~ 150 lines with whitespace and comments) so instead of looking at the final version and going through it line by line,
we will instead begin with a very simple version that only keeps track of connected clients and then add features
as we go.
To set some expectations about our example:
* It will keep track of connected clients
* It will support a couple of commands, à la IRC
* It will support direct messages using Twitter-like @usernames
* It won't use MongoDB, fibers or distributed map/reduce for anything but will be totally [Web Scale™](http://bit.ly/webscaletm) nonetheless. Maybe even [ROFLscale](http://bit.ly/roflscalevideo).
### Step one: detecting connections and disconnectons ###
First step looks like this:
{include:file:examples/guides/getting\_started/04\_simple\_chat\_server\_step\_one.rb}
We see familiar {EventMachine.run} and {EventMachine.start_server}, but also {EventMachine::Connection#post_init} and {EventMachine::Connection#unbind} we haven't
met yet. We don't use them in this code, so when are they run? Like {EventMachine::Connection#receive_data}, these methods are callbacks. EventMachine calls them
when certain events happen:
* {EventMachine#post_init} is called by the event loop immediately after the network connection has been established.
In the chat server example case, this is when a new client connects.
* {EventMachine#unbind} is called when client disconnects, connection is closed or is lost (because of a network issue, for example).
All our chat server does so far is logging connections or disconnections. What we want it to do next is to keep track of connected clients.
### Step two: keep track of connected clients ###
Next iteration of the code looks like this:
{include:file:examples/guides/getting\_started/05\_simple\_chat\_server\_step\_two.rb}
While the code we added is very straightforward, we have to clarify one this first: subclasses of {EventMachine::Connection} are instantiated by
EventMachine for every new connected peer. So for 10 connected chat clients, there will be 10 separate `SimpleChatServer` instances in our
server process. Like any other objects, they can be stored in a collection, can provide public API other objects use, can instantiate or inject
dependencies and in general live a happy life all Ruby objects live until garbage collection happens.
In the example above we use a @@class_variable to keep track of connected clients. In Ruby, @@class variables are accessible from instance
methods so we can add new connections to the list from `SimpleChatServer#post_init` and remove them in `SimpleChatServer#unbind`. We can also
filter connections by some criteria, as `SimpleChatServer#other_peers demonstrates`.
So, we keep track of connections but how do we identify them? For a chat app, it's pretty common to use usernames for that. Lets ask our clients
to enter usernames when they connect.
### Step three: adding usernames ##
To add usernames, we need to add a few things:
* We need to invite newly connected clients to enter their username.
* A reader (getter) method on our {EventMachine::Connection} subclass.
* An idea of connection state (keeping track of whether a particular participant had entered username before).
Here is one way to do it:
{include:file:examples/guides/getting\_started/06\_simple\_chat\_server\_step\_three.rb}
This is quite an update so lets take a look at each method individually. First, `SimpleChatServer#post_init`:
def post_init
@username = nil
puts "A client has connected..."
ask_username
end
To keep track of username we ask chat participants for, we add @username instance variable to our connection class. Connection
instances are just Ruby objects associated with a particular connected peer, so using @ivars is very natural. To make username
value accessible to other objects, we added a reader method that was not shown on the snippet above.
Lets dig into `SimpleChatServer#ask_username`:
def ask_username
self.send_line("[info] Enter your username:")
end # ask_username
# ...
def send_line(line)
self.send_data("#{line}\n")
end # send_line(line)
Nothing new here, we are using {EventMachine::Connection#send_data} which we have seen before.
In `SimpleChatServer#receive_data` we now have to check if the username was entered or we need
to ask for it:
def receive_data(data)
if entered_username?
handle_chat_message(data.strip)
else
handle_username(data.strip)
end
end
# ...
def entered_username?
!@username.nil? && !@username.empty?
end # entered_username?
Finally, handler of chat messages is not yet implemented:
def handle_chat_message(msg)
raise NotImplementedError
end
Lets try this example out using Telnet:
~ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
[info] Enter your username:
antares_
[info] Ohai, antares_
and the server output:
A client has connected...
antares_ has joined
This version requires you to remember how to terminate your Telnet session (Ctrl + Shift + ], then Ctrl + C).
It is annoying, so why don't we add the same `exit` command to our chat server?
### Step four: adding exit command and delivering chat messages ####
{include:file:examples/guides/getting\_started/07\_simple\_chat\_server\_step\_four.rb}
TBD
Lets test-drive this version. Client A:
~ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
[info] Enter your username:
michael
[info] Ohai, michael
Hi everyone
michael: Hi everyone
joe has joined the room
# here ^^^ client B connects, lets greet him
hi joe
michael: hi joe
joe: hey michael
# ^^^ client B replies
exit
# ^^^ out command in action
Connection closed by foreign host.
Client B:
~ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
[info] Enter your username:
joe
[info] Ohai, joe
michael: hi joe
# ^^^ client A greets us, lets reply
hey michael
joe: hey michael
exit
# ^^^ out command in action
Connection closed by foreign host.
And finally, the server output:
A client has connected...
michael has joined
A client has connected...
_antares has joined
[info] _antares has left
[info] michael has left
Our little char server now supports usernames, sending messages and the `exit` command. Next up, private (aka direct) messages.
### Step five: adding direct messages and one more command ###
To add direct messages, we come up with a simple convention: private messages begin with @username and may have optional colon before
message text, like this:
@joe: hey, how do you like eventmachine?
This convention makes parsing of messages simple so that we can concentrate on delivering them to a particular client connection.
Remember when we added `username` reader on our connection class? That tiny change makes this step possible: when a new direct
message comes in, we extract username and message text and then find then connection for @username in question:
#
# Message handling
#
def handle_chat_message(msg)
if command?(msg)
self.handle_command(msg)
else
if direct_message?(msg)
self.handle_direct_message(msg)
else
self.announce(msg, "#{@username}:")
end
end
end # handle_chat_message(msg)
def direct_message?(input)
input =~ DM_REGEXP
end # direct_message?(input)
def handle_direct_message(input)
username, message = parse_direct_message(input)
if connection = @@connected_clients.find { |c| c.username == username }
puts "[dm] @#{@username} => @#{username}"
connection.send_line("[dm] @#{@username}: #{message}")
else
send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}"
end
end # handle_direct_message(input)
def parse_direct_message(input)
return [$1, $2] if input =~ DM_REGEXP
end # parse_direct_message(input)
This snippet demonstrates how one connection instance can obtain another connection instance and send data to it.
This is a very powerful feature, consider just a few use cases:
* Peer-to-peer protocols
* Content-aware routing
* Efficient streaming with optional filtering
Less common use cases include extending C++ core of EventMachine to provide access to hardware that streams events that
can be re-broadcasted to any interested parties connected via TCP, UDP or something like AMQP or WebSockets. With this,
sky is the limit. Actually, EventMachine has several features for efficient proxying data between connections.
We will not cover them in this guide.
One last feature that we are going to add to our chat server is the `status` command that tells you current server time and how many people
are there in the chat room:
#
# Commands handling
#
def command?(input)
input =~ /(exit|status)$/i
end # command?(input)
def handle_command(cmd)
case cmd
when /exit$/i then self.close_connection
when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room")
end
end # handle_command(cmd)
Hopefully this piece of code is easy to follow. Try adding a few more commands, for example, the `whoishere` command that lists people
currently in the chat room.
In the end, our chat server looks like this:
{include:file:examples/guides/getting\_started/08\_simple\_chat\_server\_step\_five.rb}
We are almost done with the server but there are some closing thoughts.
### Step six: final version ###
Just in case, here is the final version of the chat server code we have built:
{include:file:examples/guides/getting\_started/03\_simple\_chat\_server.rb}
### Step seven: future directions and some closing thoughts ###
The chat server is just about 150 lines of Ruby including empty lines and comments, yet it has a few features most of chat server
examples never add. We did not, however, implement many other features that popular IRC clients like [Colloquy](http://colloquy.info) have:
* Chat moderation
* Multiple rooms
* Connection timeout detection
How would one go about implementing them? We thought it is worth discussing what else EventMachine has to offer and what ecosystem projects
one can use to build a really feature-rich Web-based IRC chat client.
With multiple rooms it's more or less straightforward, just add one more hash and a bunch of commands and use the information about which rooms participant
is in when you are delivering messages. There is nothing in EventMachine itself that can make the job much easier for developer.
To implement chat moderation feature you may want to do a few things:
* Work with client IP addresses. Maybe we want to consider everyone who connects from certain IPs a moderator.
* Access persistent data about usernames of moderators and their credentials.
Does EventMachine have anything to offer here? It does. To obtain peer IP address, take a look at {EventMachine::Connection#get_peername}. The name of this method is
a little bit misleading and originates from low-level socket programming APIs.
#### A whirlwind tour of the EventMachine ecosystem ####
To work with data stores you can use several database drivers that ship with EventMachine itself, however, quite often there are some 3rd party projects in
the EventMachine ecosystem that have more features, are faster or just better maintained. So we figured it will be helpful to provide a few pointers
to some of those projects:
* For MySQL, check out [em-mysql](https://github.com/eventmachine/em-mysql) project.
* For PostgreSQL, have a look at Mike Perham's [EventMachine-based PostgreSQL driver](https://github.com/mperham/em_postgresql).
* For Redis, there is a young but already popular [em-hiredis](https://github.com/mloughran/em-hiredis) library that combines EventMachine's non-blocking I/O with
extreme performance of the official Redis C client, [hiredis](https://github.com/antirez/hiredis).
* For MongoDB, see [em-mongo](https://github.com/bcg/em-mongo)
* For Cassandra, Mike Perham [added transport agnosticism feature](http://www.mikeperham.com/2010/02/09/cassandra-and-eventmachine/) to the [cassandra gem](https://rubygems.org/gems/cassandra).
[Riak](http://www.basho.com/products_riak_overview.php) and CouchDB talk HTTP so it's possible to use [em-http-request](https://github.com/igrigorik/em-http-request).
If you are aware of EventMachine-based non-blocking drivers for these databases, as well as for HBase, let us know on the [EventMachine mailing list](http://groups.google.com/group/eventmachine).
Also, EventMachine supports TLS (aka SSL) and works well on [JRuby](http://jruby.org) and Windows.
Learn more in our {file:docs/Ecosystem.md EventMachine ecosystem} and {file:docs/TLS.md TLS (aka SSL)} guides.
#### Connection loss detection ####
Finally, connection loss detection. When our chat participant closes her laptop lid, how do we know that she is no longer active? The answer is, when EventMachine
detects TCP connectin closure, it calls {EventMachine::Connection#unbind}. Version 1.0.beta3 and later also pass an optional argument to that method. The argument
indicates what error (if any) caused the connection to be closed.
Learn more in our {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery} guide.
#### What the Chat Server Example doesn't demonstrate ####
This chat server also leaves out something production quality clients and servers must take care of: buffering. We intentionally did not include any buffering in
our chat server example: it would only distract you from learning what you really came here to learn: how to use EventMachine to build blazing fast asynchronous
networking programs quickly. However, {EventMachine::Connection#receive_data} does not offer any guarantees that you will be receiving "whole messages" all the time,
largely because the underlying transport (UDP or TCP) does not offer such guarantees. Many protocols, for example, AMQP, mandate that large content chunks are
split into smaller _frames_ of certain size. This means that [amq-client](https://github.com/ruby-amqp/amq-client) library, for instance, that has EventMachine-based driver,
has to deal with figuring out when exactly we received "the whole message". To do so, it uses buffering and employs various checks to detect _frame boundaries_.
So **don't be deceived by the simplicity of this chat example**: it intentionally leaves framing out, but real world protocols usually require it.
## A (Proxying) Chat Client Example ##
TBD
## Wrapping up ##
This tutorial ends here. Congratulations! You have learned quite a bit about EventMachine.
## What to read next ##
The documentation is organized as a {file:docs/DocumentationGuidesIndex.md number of guides}, covering all kinds of
topics. TBD
## Tell us what you think! ##
Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3)
or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered?
Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is
key to making documentation better.

View File

@@ -0,0 +1,211 @@
01Oct06: Replaced EventMachine#open_datagram_server with a version that can
take a Class or a Module, instead of just a Module. Thanks to Tobias
Gustafsson for pointing out the missing case.
04Oct06: Supported subsecond timer resolutions, per request by Jason Roelofs.
05Oct06: Added EventMachine#set_quantum, which sets the timer resolution.
15Nov06: Added Connection#set_comm_inactivity_timeout.
15Nov06: Checked in a Line-and-Text Protocol Handler.
18Nov06: Checked in a Header-and-Body Protocol Handler.
22Nov06: Changed EventMachine#reconnect: no longer excepts when called on an
already-connected handler.
28Nov06: Supported a binary-unix gem.
19Dec06: Added EventMachine#set_effective_user.
05Jan07: Upped max outstanding timers to 1000.
15May07: Applied Solaris patches from Brett Eisenberg
22May07: Cleaned up the license text in all the source files.
22May07: Released version 0.7.2
23May07: Per suggestion from Bill Kelly, fixed a bug with the initialization
of the network libraries under Windows. The goal is to enable EM to
be used without Ruby.
28May07: Applied patch from Bill Kelly, refactors the declarations of
event names to make EM easier to use from C programs without Ruby.
31May07: Added a preliminary implementation of EventMachine#popen.
01Jun07: Added EM, a "pseudo-alias" for EventMachine.
01Jun07: Added EM#next_tick.
01Jun07: Added EM::Connection#get_outbound_data_size
05Jun07: Removed the code which loads a pure-Ruby EM library in case the
compiled extension is unavailable. Suggested by Moshe Litvin.
06Jun07: Preliminary epoll implementation.
12Jun07: Added an evented popen implementation that, like Ruby's, is
full-duplex and makes the subprocess PID available to the caller.
06Jul07: Performance-tweaked the callback dispatcher in eventmachine.rb.
10Jul07: Released version 0.8.0.
12Jul07: Applied patches from Tim Pease to fix Solaris build problems.
15Jul07: Created a new provisional source branch, experiments/jruby-1.
This is a preliminary implementation of the EM reactor in Java,
suitable for use with JRuby.
17Jul07: Added EventMachine#stop_server, per request from Kirk Haines,
and associated unit tests.
22Jul07: Added EventMachine#stream_file_data. This is a very fast and scalable
way of sending data from static files over network connections. It
has separate implementations for small files and large file, and
has tunings to minimize memory consumption.
26Jul07: Added some patches by Kirk Haines to improve the behavior of
EM::Connection#send_file_data_to_connection.
26Jul07: Added a C++ module for directly integrating EM into C++ programs
with no Ruby dependencies. Needs example code.
29Jul07: Added EventMachine::Protocols::LineText2.
29Jul07: Added EventMachine::Protocols::Stomp.
30Jul07: Added sys/stat.h to project.h to fix compilation bug on Darwin.
13Aug07: Added EventMachine#reactor_running?
15Aug07: Added parameters for EventMachine::Connection:start_tls that can be
used to specify client-side private keys and certificates.
17Aug07: Added EventMachine#run_block, a sugaring for a common use case.
24Aug07: Added a preliminary keyboard handler. Needs docs and testing on
windows.
26Aug07: Created EventMachine::Spawnable, an implementation of Erlang-like
processes.
27Aug07: Silenced some -w warnings, requested by James Edward Gray II.
30Aug07: Added cookies to EM::HttpClient#request.
04Sep07: Added an initial implementation of an evented SMTP client.
04Sep07: Added an initial implementation of an evented SMTP server.
10Sep07: Changed EM#spawn to run spawned blocks in the context of the
SpawnedProcess object, not of whatever was the active object at the
time of the spawn.
14Sep07: Heartbeats weren't working with EPOLL. Noticed by Brian Candler.
15Sep07: Added some features, tests and documents to Deferrable.
16Sep07: Added [:content] parameter to EM::Protocols::SmtpClient#send.
16Sep07: Bumped version to 0.9.0 in anticipation of a release.
18Sep07: Released version 0.9.0.
19Sep07: Added #receive_reset to EM::Protocols::SmtpServer.
19Sep07: User overrides of EM::Protocols::SmtpServer#receive_recipient can now
return a Deferrable. Also fixed bug: SmtpClient now raises a protocol
error if none of its RCPT TO: commands are accepted by the server.
26Sep07: Fixed missing keyboard support for Windows.
03Oct07: Added a default handler for RuntimeErrors emitted from user-written
code. Suggested by Brian Candler.
19Oct07: Set the SO_BROADCAST option automatically on all UDP sockets.
10Nov07: Forced integer conversion of send_datagram's port parameter.
Suggested by Matthieu Riou.
12Nov07: Added saslauth.rb, a protocol module to replace the Cyrus SASL
daemons saslauthd and pwcheck.
15Nov07: Fixed bug reported by Mark Zvillius. We were failing to dispatch
zero-length datagrams under certain conditions.
19Nov07: Added EventMachine#set_max_timers. Requested by Matthieu Riou and
others.
19Nov07: Fixed bug with EM::Connection#start_tls. Was not working with server
connections. Reported by Michael S. Fischer.
26Nov07: Supported a hack for EventMachine#popen so it can return an exit
status from subprocesses. Requested by Michael S. Fischer.
30Nov07: Changed Pipe descriptors so that the child-side of the socketpair is
NOT set nonblocking. Suggested by Duane Johnson.
05Dec07: Re-enabled the pure-Ruby implementation.
06Dec07: Released Version 0.10.0.
13Dec07: Added EM::DeferrableChildProcess
24Dec07: Added a SASL client for simple password authentication.
27Dec07: Removed the hookable error handler. No one was using it and it significantly
degraded performance.
30Dec07: Implemented Kqueue support for OSX and BSD.
04Jan08: Fixed bug in epoll ("Bad file descriptor"), patch supplied by Chris
Heath.
04Jan08: Fixed bug reported by Michael S. Fischer. We were terminating
SSL connections that sent data before the handshake was complete.
08Jan08: Added an OpenBSD branch for extconf.rb, contributed by Guillaume
Sellier.
19Jan08: Added EM::Connection::get_sockname per request by Michael Fischer.
19Jan08: Supported IPv6 addresses.
30Apr08: Set the NODELAY option on sockets that we connect to other servers.
Omission noted by Roger Pack.
14May08: Generated a 0.12 release.
15May08: Supported EM#get_sockname for acceptors (TCP server sockets).
Requested by Roger Pack.
15May08; Accepted a patch from Dan Aquino that allows the interval of a
PeriodicTimer to be changed on the fly.
15Jun08: Supported nested calls to EM#run. Many people contributed ideas to
this, notably raggi and tmm1.
20Jul08: Accepted patch from tmm1 for EM#fork_reactor.
28Jul08: Added a Postgres3 implementation, written by FCianfrocca.
14Aug08: Added a patch by Mike Murphy to support basic auth in the http
client.
28Aug08: Added a patch by tmm1 to fix a longstanding problem with Java
data-sends.
13Sep08: Added LineText2#set_binary_mode, a back-compatibility alias.
13Sep08: Modified the load order of protocol libraries in eventmachine.rb
to permit a modification of HeaderAndContentProtocol.
13Sep08: Modified HeaderAndContent to use LineText2, which is less buggy
than LineAndTextProtocol. This change may be reversed if we can fix
the bugs in buftok.
13Sep08: Improved the password handling in the Postgres protocol handler.
15Sep08: Added attach/detach, contributed by Aman Gupta (tmm1) and Riham Aldakkak,
to support working with file descriptors not created in the reactor.
16Sep08: Added an optional version string to the HTTP client. This is a hack
that allows a client to specify a version 1.0 request, which
keeps the server from sending a chunked response. The right way to
solve this, of course, is to support chunked responses.
23Sep08: ChangeLog Summary for Merge of branches/raggi
Most notable work and patches by Aman Gupta, Roger Pack, and James Tucker.
Patches / Tickets also submitted by: Jeremy Evans, aanand, darix, mmmurf,
danielaquino, macournoyer.
- Moved docs into docs/ dir
- Major refactor of rakefile, added generic rakefile helpers in tasks
- Added example CPP build rakefile in tasks/cpp.rake
- Moved rake tests out to tasks/tests.rake
- Added svn ignores where appropriate
- Fixed jruby build on older java platforms
- Gem now builds from Rakefile rather than directly via extconf
- Gem unified for jruby, C++ and pure ruby.
- Correction for pure C++ build, removing ruby dependency
- Fix for CYGWIN builds on ipv6
- Major refactor for extconf.rb
- Working mingw builds
- extconf optionally uses pkg_config over manual configuration
- extconf builds for 1.9 on any system that has 1.9
- extconf no longer links pthread explicitly
- looks for kqueue on all *nix systems
- better error output on std::runtime_error, now says where it came from
- Fixed some tests on jruby
- Added test for general send_data flaw, required for a bugfix in jruby build
- Added timeout to epoll tests
- Added fixes for java reactor ruby api
- Small addition of some docs in httpclient.rb and httpcli2.rb
- Some refactor and fixes in smtpserver.rb
- Added parenthesis where possible to avoid excess ruby warnings
- Refactor of $eventmachine_library logic for accuracy and maintenance, jruby
- EM::start_server now supports unix sockets
- EM::connect now supports unix sockets
- EM::defer @threadqueue now handled more gracefully
- Added better messages on exceptions raised
- Fix edge case in timer fires
- Explicitly require buftok.rb
- Add protocols to autoload, rather than require them all immediately
- Fix a bug in pr_eventmachine for outbound_q
- Refactors to take some of the use of defer out of tests.
- Fixes in EM.defer under start/stop conditions. Reduced scope of threads.
23Sep08: Added patch from tmm1 to avoid popen errors on exit.
30Sep08: Added File.exists? checks in the args for start_tls, as suggested by
Brian Lopez (brianmario).
10Nov08: ruby 1.9 compatibility enhancements
28Nov08: Allow for older ruby builds where RARRAY_LEN is not defined
03Dec08: allow passing arguments to popen handlers
13Jan09: SSL support for httpclient2 (David Smalley)
22Jan09: Fixed errors on OSX with the kqueue reactor, fixed errors in the pure
ruby reactor. Added EM.current_time. Added EM.epoll? and EM.kqueue?
27Jan09: Reactor errors are now raised as ruby RuntimeErrors.
28Jan09: Documentation patch from alloy
29Jan09: (Late sign-off) Use a longer timeout for connect_server (Ilya
Grigorik)
07Feb09: Fix signal handling issues with threads+epoll
07Feb09: Use rb_thread_schedule in the epoll reactor
07Feb09: Use TRAP_BEG/END and rb_thread_schedule in kqueue reactor
08Feb09: Added fastfilereader from swiftiply
08Feb09: 1.9 fix for rb_trap_immediate
08Feb09: Enable rb_thread_blocking_region for 1.9.0 and 1.9.1
10Feb09: Support win32 builds for fastfilereader
10Feb09: Added a new event to indicate completion of SSL handshake on TCP
connections
10Feb09: Working get_peer_cert method. Returns the certificate as a Ruby
String in PEM format. (Jake Douglas)
10Feb09: Added EM.get_max_timers
11Feb09: Fix compile options for sun compiler (Alasdairrr)
11Feb09: get_status returns a Process::Status object
12Feb09: Add EM::Protocols::Memcache with simple get/set functionality
19Feb09: Add catch-all EM.error_handler
20Feb09: Support miniunit (1.9)
20Feb09: Return success on content-length = 0 instead of start waiting forever
(Ugo Riboni)
25Feb09: Allow next_tick to be used to pre-schedule reactor operations before
EM.run
26Feb09: Added EM.get_connection_count
01Mar09: Switch back to extconf for compiling gem extensions
01Mar09: fixed a small bug with basic auth (mmmurf)

View File

@@ -0,0 +1,246 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency
to the Ruby programmer's toolbox: spawned processes and deferrables. This
note will show you how to use deferrables. For more information, see the
separate document LIGHTWEIGHT_CONCURRENCY.
=== What are Deferrables?
EventMachine's Deferrable borrows heavily from the "deferred" object in
Python's "Twisted" event-handling framework. Here's a minimal example that
illustrates Deferrable:
require 'eventmachine'
class MyClass
include EM::Deferrable
def print_value x
puts "MyClass instance received #{x}"
end
end
EM.run {
df = MyClass.new
df.callback {|x|
df.print_value(x)
EM.stop
}
EM::Timer.new(2) {
df.set_deferred_status :succeeded, 100
}
}
This program will spin for two seconds, print out the string "MyClass
instance received 100" and then exit. The Deferrable pattern relies on
an unusual metaphor that may be unfamiliar to you, unless you've used
Python's Twisted. You may need to read the following material through
more than once before you get the idea.
EventMachine::Deferrable is simply a Ruby Module that you can include
in your own classes. (There also is a class named
EventMachine::DefaultDeferrable for when you want to create one without
including it in code of your own.)
An object that includes EventMachine::Deferrable is like any other Ruby
object: it can be created whenever you want, returned from your functions,
or passed as an argument to other functions.
The Deferrable pattern allows you to specify any number of Ruby code
blocks (callbacks or errbacks) that will be executed at some future time
when the status of the Deferrable object changes.
How might that be useful? Well, imagine that you're implementing an HTTP
server, but you need to make a call to some other server in order to fulfill
a client request.
When you receive a request from one of your clients, you can create and
return a Deferrable object. Some other section of your program can add a
callback to the Deferrable that will cause the client's request to be
fulfilled. Simultaneously, you initiate an event-driven or threaded client
request to some different server. And then your EM program will continue to
process other events and service other client requests.
When your client request to the other server completes some time later, you
will call the #set_deferred_status method on the Deferrable object, passing
either a success or failure status, and an arbitrary number of parameters
(which might include the data you received from the other server).
At that point, the status of the Deferrable object becomes known, and its
callback or errback methods are immediately executed. Callbacks and errbacks
are code blocks that are attached to Deferrable objects at any time through
the methods #callback and #errback.
The deep beauty of this pattern is that it decouples the disposition of one
operation (such as a client request to an outboard server) from the
subsequent operations that depend on that disposition (which may include
responding to a different client or any other operation).
The code which invokes the deferred operation (that will eventually result
in a success or failure status together with associated data) is completely
separate from the code which depends on that status and data. This achieves
one of the primary goals for which threading is typically used in
sophisticated applications, with none of the nondeterminacy or debugging
difficulties of threads.
As soon as the deferred status of a Deferrable becomes known by way of a call
to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its
callbacks or errbacks in the order in which they were added to the Deferrable.
Callbacks and errbacks can be added to a Deferrable object at any time, not
just when the object is created. They can even be added after the status of
the object has been determined! (In this case, they will be executed
immediately when they are added.)
A call to Deferrable#set_deferred_status takes :succeeded or :failed as its
first argument. (This determines whether the object will call its callbacks
or its errbacks.) #set_deferred_status also takes zero or more additional
parameters, that will in turn be passed as parameters to the callbacks or
errbacks.
In general, you can only call #set_deferred_status ONCE on a Deferrable
object. A call to #set_deferred_status will not return until all of the
associated callbacks or errbacks have been called. If you add callbacks or
errbacks AFTER making a call to #set_deferred_status, those additional
callbacks or errbacks will execute IMMEDIATELY. Any given callback or
errback will be executed AT MOST once.
It's possible to call #set_deferred_status AGAIN, during the execution a
callback or errback. This makes it possible to change the parameters which
will be sent to the callbacks or errbacks farther down the chain, enabling
some extremely elegant use-cases. You can transform the data returned from
a deferred operation in arbitrary ways as needed by subsequent users, without
changing any of the code that generated the original data.
A call to #set_deferred_status will not return until all of the associated
callbacks or errbacks have been called. If you add callbacks or errbacks
AFTER making a call to #set_deferred_status, those additional callbacks or
errbacks will execute IMMEDIATELY.
Let's look at some more sample code. It turns out that many of the internal
protocol implementations in the EventMachine package rely on Deferrable. One
of these is EM::Protocols::HttpClient.
To make an evented HTTP request, use the module function
EM::Protocols::HttpClient#request, which returns a Deferrable object.
Here's how:
require 'eventmachine'
EM.run {
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
:request=>"/index.html" )
df.callback {|response|
puts "Succeeded: #{response[:content]}"
EM.stop
}
df.errback {|response|
puts "ERROR: #{response[:status]}"
EM.stop
}
}
(See the documentation of EventMachine::Protocols::HttpClient for information
on the object returned by #request.)
In this code, we make a call to HttpClient#request, which immediately returns
a Deferrable object. In the background, an HTTP client request is being made
to www.example.com, although your code will continue to run concurrently.
At some future point, the HTTP client request will complete, and the code in
EM::Protocols::HttpClient will process either a valid HTTP response (including
returned content), or an error.
At that point, EM::Protocols::HttpClient will call
EM::Deferrable#set_deferred_status on the Deferrable object that was returned
to your program, as the return value from EM::Protocols::HttpClient.request.
You don't have to do anything to make this happen. All you have to do is tell
the Deferrable what to do in case of either success, failure, or both.
In our code sample, we set one callback and one errback. The former will be
called if the HTTP call succeeds, and the latter if it fails. (For
simplicity, we have both of them calling EM#stop to end the program, although
real programs would be very unlikely to do this.)
Setting callbacks and errbacks is optional. They are handlers to defined
events in the lifecycle of the Deferrable event. It's not an error if you
fail to set either a callback, an errback, or both. But of course your
program will then fail to receive those notifications.
If through some bug it turns out that #set_deferred_status is never called
on a Deferrable object, then that object's callbacks or errbacks will NEVER
be called. It's also possible to set a timeout on a Deferrable. If the
timeout elapses before any other call to #set_deferred_status, the Deferrable
object will behave as is you had called set_deferred_status(:failed) on it.
Now let's modify the example to illustrate some additional points:
require 'eventmachine'
EM.run {
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
:request=>"/index.html" )
df.callback {|response|
df.set_deferred_status :succeeded, response[:content]
}
df.callback {|string|
puts "Succeeded: #{string}"
EM.stop
}
df.errback {|response|
puts "ERROR: #{response[:status]}"
EM.stop
}
}
Just for the sake of illustration, we've now set two callbacks instead of
one. If the deferrable operation (the HTTP client-request) succeeds, then
both of the callbacks will be executed in order.
But notice that we've also made our own call to #set_deferred_status in the
first callback. This isn't required, because the HttpClient implementation
already made a call to #set_deferred_status. (Otherwise, of course, the
callback would not be executing.)
But we used #set_deferred_status in the first callback in order to change the
parameters that will be sent to subsequent callbacks in the chain. In this
way, you can construct powerful sequences of layered functionality. If you
want, you can even change the status of the Deferrable from :succeeded to
:failed, which would abort the chain of callback calls, and invoke the chain
of errbacks instead.
Now of course it's somewhat trivial to define two callbacks in the same
method, even with the parameter-changing effect we just described. It would
be much more interesting to pass the Deferrable to some other function (for
example, a function defined in another module or a different gem), that would
in turn add callbacks and/or errbacks of its own. That would illustrate the
true power of the Deferrable pattern: to isolate the HTTP client-request
from other functions that use the data that it returns without caring where
those data came from.
Remember that you can add a callback or an errback to a Deferrable at any
point in time, regardless of whether the status of the deferred operation is
known (more precisely, regardless of when #set_deferred_status is called on
the object). Even hours or days later.
When you add a callback or errback to a Deferrable object on which
#set_deferred_status has not yet been called, the callback/errback is queued
up for future execution, inside the Deferrable object. When you add a
callback or errback to a Deferrable on which #set_deferred_status has
already been called, the callback/errback will be executed immediately.
Your code doesn't have to worry about the ordering, and there are no timing
issues, as there would be with a threaded approach.
For more information on Deferrables and their typical usage patterns, look
in the EM unit tests. There are also quite a few sugarings (including
EM::Deferrable#future) that make typical Deferrable usages syntactically
easier to work with.

View File

@@ -0,0 +1,141 @@
EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs.
Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels.
It features significantly greater performance than the standard select(2) mechanism, when used in
applications that require very large numbers of open I/O descriptors.
EventMachine has always used select(2) because its behavior is well standardized and broadly supported.
But select becomes unreasonably slow when a program has a
very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit
of 1024 descriptors per process, but heavily loaded processes will start to show performance
degradation even after only a few hundred descriptors are in use.
Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs
based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands
of connectors, with no significant impact on performance.
(Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its
variants.)
This note shows you how to use epoll in your programs.
=== Compiling EventMachine to use epoll.
You don't have to do anything to get epoll support in EventMachine.
When you compile EventMachine on a platform that supports epoll, EM will
automatically generate a Makefile that includes epoll. (At this writing, this will only work
on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will
be omitted from the Makefile, and EM will work just as it always has.
=== Using epoll in your programs.
First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement
will be removed in a future EventMachine version). Second, you need to prepare your program to use
more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably
want your process to drop the superuser privileges after you increase your process's descriptor limit.
=== Using EventMachine#epoll
Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will
automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because
it compiles to a no-op on platforms that don't support epoll.
require 'rubygems'
require 'eventmachine'
EM.epoll
EM.run {
...
}
EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing
programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op,
and run epoll by default on platforms that support it.
=== Using EventMachine#set_descriptor_table_size
In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum
number of file and socket descriptors you may have open at any given time. The size of this table is
generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits.
If you want your EventMachine program to support more than 1024 total descriptors, you must use
EventMachine#set_descriptor_table_size, as follows:
require 'rubygems'
require 'eventmachine'
new_size = EM.set_descriptor_table_size( 60000 )
$>.puts "New descriptor-table size is #{new_size}"
EM.run {
...
}
If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000.
Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current
size of the descriptor table.
Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used
by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the
number of descriptors that Ruby's own I/O functions can use.
#set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a
table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number.
=== Using EventMachine#set_effective_user
In general, you must run your program with elevated or superuser privileges if you want to increase
your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the
sample program given above, that increases the descriptor limit to 60,000. You will probably find that
the table size will not be increased if you don't run your program as root or with elevated privileges.
But of course network servers, especially long-running ones, should not run with elevated privileges.
You will want to drop superuser privileges as soon as possible after initialization. To do this,
use EventMachine#set_effective_user:
require 'rubygems'
require 'eventmachine'
# (Here, program is running as superuser)
EM.set_descriptor_table_size( 60000 )
EM.set_effective_user( "nobody" )
# (Here, program is running as nobody)
EM.run {
...
}
Of course, you will need to replace "nobody" in the example with the name of an unprivileged user
that is valid on your system. What if you want to drop privileges after opening a server socket
on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets:
require 'rubygems'
require 'eventmachine'
# (Here, program is running as superuser)
EM.set_descriptor_table_size( 60000 )
EM.run {
EM.start_server( "0.0.0.0", 80, MyHttpServer )
EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer )
EM.set_effective_user( "nobody" )
# (Here, program is running as nobody)
...
}
Because EventMachine#set_effective_user is used to enforce security
requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user,
#set_effective_user will abort your program, rather than continue to run with elevated privileges.
EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows.

View File

@@ -0,0 +1,13 @@
If you have obtained an EventMachine source-tarball (.tar.gz):
unzip and untar the tarball, and enter the directory that is
created. In that directory, say:
ruby setup.rb
(You may need to be root to execute this command.)
To create documentation for EventMachine, simply type:
rake rdoc
in the distro directory. Rdocs will be created in subdirectory rdoc.
If you have obtained a gem version of EventMachine, install it in the
usual way (gem install eventmachine). You may need superuser privileges
to execute this command.

View File

@@ -0,0 +1,42 @@
EventMachine (EM) can respond to keyboard events. This gives your event-driven
programs the ability to respond to input from local users.
Programming EM to handle keyboard input in Ruby is simplicity itself. Just use
EventMachine#open_keyboard, and supply the name of a Ruby module or class that
will receive the input:
require 'rubygems'
require 'eventmachine'
module MyKeyboardHandler
def receive_data keystrokes
puts "I received the following data from the keyboard: #{keystrokes}"
end
end
EM.run {
EM.open_keyboard(MyKeyboardHandler)
}
If you want EM to send line-buffered keyboard input to your program, just
include the LineText2 protocol module in your handler class or module:
require 'rubygems'
require 'eventmachine'
module MyKeyboardHandler
include EM::Protocols::LineText2
def receive_line data
puts "I received the following line from the keyboard: #{data}"
end
end
EM.run {
EM.open_keyboard(MyKeyboardHandler)
}
As we said, simplicity itself. You can call EventMachine#open_keyboard at any
time while the EM reactor loop is running. In other words, the method
invocation may appear anywhere in an EventMachine#run block, or in any code
invoked in the #run block.

View File

@@ -0,0 +1,25 @@
LEGAL NOTICE INFORMATION
------------------------
EventMachine is Copyright (C) 2006-07 by Francis Cianfrocca.
EventMachine is copyrighted software owned by Francis Cianfrocca
(blackhedd ... gmail.com). You may redistribute and/or modify this
software as long as you comply with either the terms of the GPL
(see the file GPL), or Ruby's license (see the file COPYING).
Your use of all the files in this distribution is controlled by these
license terms, except for those files specifically mentioned below:
setup.rb
This file is Copyright (C) 2000-2005 by Minero Aoki
You can distribute/modify this file under the terms of
the GNU LGPL, Lesser General Public License version 2.1.
lib/em/buftok.rb
This file is Copyright (C) 2007 by Tony Arcieri. This file is
covered by the terms of Ruby's License (see the file COPYING).

View File

@@ -0,0 +1,130 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency to
the Ruby programmer's toolbox: spawned processes and deferrables. This note
will show you how to use them.
=== What is Lightweight Concurrency?
We use the term "Lightweight Concurrency" (LC) to refer to concurrency
mechanisms that are lighter than Ruby threads. By "lighter," we mean: less
resource-intensive in one or more dimensions, usually including memory and
CPU usage. In general, you turn to LC in the hope of improving the
performance and scalability of your programs.
In addition to the two EventMachine mechanisms we will discuss here, Ruby
has at least one other LC construct: Fibers, which are currently under
development in Ruby 1.9.
The technical feature that makes all of these LC mechanisms different from
standard Ruby threads is that they are not scheduled automatically.
When you create and run Ruby threads, you can assume (within certain
constraints) that your threads will all be scheduled fairly by Ruby's runtime.
Ruby itself is responsible for giving each of your threads its own share of
the total runtime.
But with LC, your program is responsible for causing different execution
paths to run. In effect, your program has to act as a "thread scheduler."
Scheduled entities in LC run to completion and are never preempted. The
runtime system has far less work to do since it has no need to interrupt
threads or to schedule them fairly. This is what makes LC lighter and faster.
You'll learn exactly how LC scheduling works in practice as we work through
specific examples.
=== EventMachine Lightweight Concurrency
Recall that EM provides a reactor loop that must be running in order for
your programs to perform event-driven logic. An EM program typically has a
structure like this:
require 'eventmachine'
# your initializations
EM.run {
# perform event-driven I/O here, including network clients,
# servers, timers, and thread-pool operations.
}
# your cleanup
# end of the program
EventMachine#run executes the reactor loop, which causes your code to be
called as events of interest to your program occur. The block you pass to
EventMachine#run is executed right after the reactor loop starts, and is
the right place to start socket acceptors, etc.
Because the reactor loop runs constantly in an EM program (until it is
stopped by a call to EventMachine#stop), it has the ability to schedule
blocks of code for asynchronous execution. Unlike a pre-emptive thread
scheduler, it's NOT able to interrupt code blocks while they execute. But
the scheduling capability it does have is enough to enable lightweight
concurrency.
For information on Spawned Processes, see the separate document
SPAWNED_PROCESSES.
For information on Deferrables, see the separate document DEFERRABLES.
=== [SIDEBAR]: I Heard That EventMachine Doesn't Work With Ruby Threads.
This is incorrect. EM is fully interoperable with all versions of Ruby
threads, and has been since its earliest releases.
It's very true that EM encourages an "evented" (non-threaded) programming
style. The specific benefits of event-driven programming are far better
performance and scalability for well-written programs, and far easier
debugging.
The benefit of using threads for similar applications is a possibly more
intuitive programming model, as well as the fact that threads are already
familiar to most programmers. Also, bugs in threaded programs often fail
to show up until programs go into production. These factors create the
illusion that threaded programs are easier to write.
However, some operations that occur frequently in professional-caliber
applications simply can't be done without threads. (The classic example
is making calls to database client-libraries that block on network I/O
until they complete.)
EventMachine not only allows the use of Ruby threads in these cases, but
it even provides a built-in thread-pool object to make them easier to
work with.
You may have heard a persistent criticism that evented I/O is fundamentally
incompatible with Ruby threads. It is true that some well-publicized attempts
to incorporate event-handling libraries into Ruby were not successful. But
EventMachine was designed from the ground up with Ruby compatibility in mind,
so EM never suffered from the problems that defeated the earlier attempts.
=== [SIDEBAR]: I Heard That EventMachine Doesn't Work Very Well On Windows.
This too is incorrect. EventMachine is an extension written in C++ and Java,
and therefore it requires compilation. Many Windows computers (and some Unix
computers, especially in production environments) don't have a build stack.
Attempting to install EventMachine on a machine without a compiler usually
produces a confusing error.
In addition, Ruby has a much-debated issue with Windows compiler versions.
Ruby on Windows works best with Visual Studio 6, a compiler version that is
long out-of-print, no longer supported by Microsoft, and difficult to obtain.
(This problem is not specific to EventMachine.)
Shortly after EventMachine was first released, the compiler issues led to
criticism that EM was incompatible with Windows. Since that time, every
EventMachine release has been supplied in a precompiled binary form for
Windows users, that does not require you to compile the code yourself. EM
binary Gems for Windows are compiled using Visual Studio 6.
EventMachine does supply some advanced features (such as Linux EPOLL support,
reduced-privilege operation, UNIX-domain sockets, etc.) that have no
meaningful implementation on Windows. Apart from these special cases, all EM
functionality (including lightweight concurrency) works perfectly well on
Windows.

View File

@@ -0,0 +1,75 @@
EventMachine is supplied in three alternative versions.
1) A version that includes a Ruby extension written in C++. This version requires compilation;
2) A version for JRuby that contains a precompiled JAR file written in Java;
3) A pure Ruby version that has no external dependencies and can run in any Ruby environment.
The Java version of EventMachine is packaged in a distinct manner and must be installed using a
special procedure. This version is described fully in a different document, and not considered
further here.
The C++ and pure-Ruby versions, however, are shipped in the same distribution. You use the same
files (either tarball or Ruby gem) to install both of these versions.
If you intend to use the C++ version, you must successfully compile EventMachine after you install it.
(The gem installation attempts to perform this step automatically.)
If you choose not to compile the EventMachine C++ extension, or if your compilation fails for any
reason, you still have a fully-functional installation of the pure-Ruby version of EM.
However, for technical reasons, a default EM installation (whether or not the compilation succeeds)
will always assume that the compiled ("extension") implementation should be used.
If you want your EM program to use the pure Ruby version, you must specifically request it. There
are two ways to do this: by setting either a Ruby global variable, or an environment string.
The following code will invoke the pure-Ruby implementation of EM:
$eventmachine_library = :pure_ruby
require 'eventmachine'
EM.library_type #=> "pure_ruby"
Notice that this requires a code change and is not the preferred way to select pure Ruby, unless
for some reason you are absolutely sure you will never want the compiled implementation.
Setting the following environment string has the same effect:
export EVENTMACHINE_LIBRARY="pure_ruby"
This technique gives you the flexibility to select either version at runtime with no code changes.
Support
The EventMachine development team has committed to support precisely the same APIs for all the
various implementations of EM.
This means that you can expect any EM program to behave identically, whether you use pure Ruby,
the compiled C++ extension, or JRuby. Deviations from this behavior are to be considered bugs
and should be reported as such.
There is a small number of exceptions to this rule, which arise from underlying platform
distinctions. Notably, EM#epoll is a silent no-op in the pure Ruby implementation.
When Should You Use the Pure-Ruby Implementation of EM?
Use the pure Ruby implementation of EM when you must support a platform for which no C++ compiler
is available, or on which the standard EM C++ code can't be compiled.
Keep in mind that you don't need a C++ compiler in order to deploy EM applications that rely on
the compiled version, so long as appropriate C++ runtime libraries are available on the target platform.
In extreme cases, you may find that you can develop software with the compiled EM version, but are
not allowed to install required runtime libraries on the deployment system(s). This would be another
case in which the pure Ruby implementation can be useful.
In general you should avoid the pure Ruby version of EM when performance and scalability are important.
EM in pure Ruby will necessarily run slower than the compiled version. Depending on your application
this may or may not be a key issue.
Also, since EPOLL is not supported in pure Ruby, your applications will be affected by Ruby's built-in
limit of 1024 file and socket descriptors that may be open in a single process. For maximum scalability
and performance, always use EPOLL if possible.

View File

@@ -0,0 +1,94 @@
RUBY/EventMachine RELEASE NOTES
--------------------------------------------------
Version: 0.9.0, released xxXXX07
Added Erlang-like distributed-computing features
--------------------------------------------------
Version: 0.8.0, released 23Jun07
Added an epoll implementation for Linux 2.6 kernels.
Added evented #popen.
--------------------------------------------------
Version: 0.7.3, released 22May07
Added a large variety of small features. See the ChangeLog.
--------------------------------------------------
Version: 0.7.1, released xxNov06
Added protocol handlers for line-oriented protocols.
Various bug fixes.
--------------------------------------------------
Version: 0.7.0, released 20Nov06
Added a fix in em.cpp/ConnectToServer to fix a fatal exception that
occurred in FreeBSD when connecting successfully to a remote server.
--------------------------------------------------
Version: 0.6.0, released xxJul06
Added deferred operations, suggested by Don Stocks, amillionhitpoints@yahoo.com.
--------------------------------------------------
Version: 0.5.4, released xxJun06
Added get_peername support for streams and datagrams.
--------------------------------------------------
Version: 0.5.3, released 17May06
Fixed bugs in extconf.rb, thanks to Daniel Harple, dharple@generalconsumption.org.
Added proper setup.rb and rake tasks, thanks to Austin Ziegler.
Fixed a handful of reported problems with builds on various platforms.
--------------------------------------------------
Version: 0.5.2, released 05May06
Made several nonvisible improvements to the Windows
implementation.
Added an exception-handling patch contributed by Jeff Rose, jeff@rosejn.net.
Added a dir-config patch contributed anonymously.
Supported builds on Solaris.
--------------------------------------------------
Version: 0.5.1, released 05May06
Made it possible to pass a Class rather than a Module
to a protocol handler.
Added Windows port.
--------------------------------------------------
Version: 0.5.0, released 30Apr06
Added a preliminary SSL/TLS extension. This will probably
change over the next few releases.
--------------------------------------------------
Version: 0.4.5, released 29Apr06
Changed ext files so the ruby.h is installed after unistd.h
otherwise it doesn't compile on gcc 4.1
--------------------------------------------------
Version: 0.4.2, released 19Apr06
Changed the Ruby-glue so the extension will play nicer
in the sandbox with Ruby threads.
Added an EventMachine::run_without_threads API to
switch off the thread-awareness for better performance
in programs that do not spin any Ruby threads.
--------------------------------------------------
Version: 0.4.1, released 15Apr06
Reworked the shared-object interface to make it easier to
use EventMachine from languages other than Ruby.
--------------------------------------------------
Version: 0.3.2, released 12Apr06
Added support for a user-supplied block in EventMachine#connect.
--------------------------------------------------
Version: 0.3.1, released 11Apr06
Fixed bug that prevented EventMachine from being run multiple
times in a single process.
--------------------------------------------------
Version: 0.3.0, released 10Apr06
Added method EventHandler::Connection::post_init
--------------------------------------------------
Version: 0.2.0, released 10Apr06
Added method EventHandler::stop

View File

@@ -0,0 +1,4 @@
This note details the usage of EventMachine's built-in support for SMTP. EM
supports both client and server connections, which will be described in
separate sections.

View File

@@ -0,0 +1,148 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency
to the Ruby programmer's toolbox: spawned processes and deferrables. This
note will show you how to use spawned processes. For more information, see
the separate document LIGHTWEIGHT_CONCURRENCY.
=== What are Spawned Processes?
Spawned Processes in EventMachine are inspired directly by the "processes"
found in the Erlang programming language. EM deliberately borrows much (but
not all) of Erlang's terminology. However, EM's spawned processes differ from
Erlang's in ways that reflect not only Ruby style, but also the fact that
Ruby is not a functional language like Erlang.
Let's proceed with a complete, working code sample that we will analyze line
by line. Here's an EM implementation of the "ping-pong" program that also
appears in the Erlang tutorial:
require 'eventmachine'
EM.run {
pong = EM.spawn {|x, ping|
puts "Pong received #{x}"
ping.notify( x-1 )
}
ping = EM.spawn {|x|
if x > 0
puts "Pinging #{x}"
pong.notify x, self
else
EM.stop
end
}
ping.notify 3
}
If you run this program, you'll see the following output:
Pinging 3
Pong received 3
Pinging 2
Pong received 2
Pinging 1
Pong received 1
Let's take it step by step.
EventMachine#spawn works very much like the built-in function spawn in
Erlang. It returns a reference to a Ruby object of class
EventMachine::SpawnedProcess, which is actually a schedulable entity. In
Erlang, the value returned from spawn is called a "process identifier" or
"pid." But we'll refer to the Ruby object returned from EM#spawn simply as a
"spawned process."
You pass a Ruby block with zero or more parameters to EventMachine#spawn.
Like all Ruby blocks, this one is a closure, so it can refer to variables
defined in the local context when you call EM#spawn.
However, the code block passed to EM#spawn does NOT execute immediately by
default. Rather, it will execute only when the Spawned Object is "notified."
In Erlang, this process is called "message passing," and is done with the
operator !, but in Ruby it's done simply by calling the #notify method of a
spawned-process object. The parameters you pass to #notify must match those
defined in the block that was originally passed to EM#spawn.
When you call the #notify method of a spawned-process object, EM's reactor
core will execute the code block originally passed to EM#spawn, at some point
in the future. (#notify itself merely adds a notification to the object's
message queue and ALWAYS returns immediately.)
When a SpawnedProcess object executes a notification, it does so in the
context of the SpawnedProcess object itself. The notified code block can see
local context from the point at which EM#spawn was called. However, the value
of "self" inside the notified code block is a reference to the SpawnedProcesss
object itself.
An EM spawned process is nothing more than a Ruby object with a message
queue attached to it. You can have any number of spawned processes in your
program without compromising scalability. You can notify a spawned process
any number of times, and each notification will cause a "message" to be
placed in the queue of the spawned process. Spawned processes with non-empty
message queues are scheduled for execution automatically by the EM reactor.
Spawned processes with no visible references are garbage-collected like any
other Ruby object.
Back to our code sample:
pong = EM.spawn {|x, ping|
puts "Pong received #{x}"
ping.notify( x-1 )
}
This simply creates a spawned process and assigns it to the local variable
pong. You can see that the spawned code block takes a numeric parameter and a
reference to another spawned process. When pong is notified, it expects to
receive arguments corresponding to these two parameters. It simply prints out
the number it receives as the first argument. Then it notifies the spawned
process referenced by the second argument, passing it the first argument
minus 1.
And then the block ends, which is crucial because otherwise nothing else
can run. (Remember that in LC, scheduled entities run to completion and are
never preempted.)
On to the next bit of the code sample:
ping = EM.spawn {|x|
if x > 0
puts "Pinging #{x}"
pong.notify x, self
else
EM.stop
end
}
Here, we're spawning a process that takes a single (numeric) parameter. If
the parameter is greater than zero, the block writes it to the console. It
then notifies the spawned process referenced by the pong local variable,
passing as arguments its number argument, and a reference to itself. The
latter reference, as you saw above, is used by pong to send a return
notification.
If the ping process receives a zero value, it will stop the reactor loop and
end the program.
Now we've created a pair of spawned processes, but nothing else has happened.
If we stop now, the program will spin in the EM reactor loop, doing nothing
at all. Our spawned processes will never be scheduled for execution.
But look at the next line in the code sample:
ping.notify 3
This line gets the ping-pong ball rolling. We call ping's #notify method,
passing the argument 3. This causes a message to be sent to the ping spawned
process. The message contains the single argument, and it causes the EM
reactor to schedule the ping process. And this in turn results in the
execution of the Ruby code block passed to EM#spawn when ping was created.
Everything else proceeds as a result of the messages that are subsequently
passed to each other by the spawned processes.
[TODO, present the outbound network i/o use case, and clarify that spawned
processes are interleaved with normal i/o operations and don't interfere
with them at all. Also, blame Erlang for the confusing term "process"]

View File

@@ -0,0 +1,8 @@
TODO List:
12Aug06: Noticed by Don Stocks. A TCP connect-request that results
in a failed DNS resolution fires a fatal error back to user code.
Uuuuuugly. We should probably cause an unbind event to get fired
instead, and add some parameterization so the caller can detect
the nature of the failure.