[[PageOutline(2-6,Snippets,)]] = Code Snippets = Put your interesting code snippets here. Please include a description of what is special about said snippet. You can add code highlighting as follows: {{{ {{{ #!ruby def hello_world puts "hi" end }}} }}} results in {{{ #!ruby def hello_world puts "hi" end }}} == Small client Example == {{{ class Echo < EventMachine::Connection def initialize(*args) super # stuff here... end def receive_data(data) p data end end EventMachine::run { EventMachine::connect '127.0.0.1', 8081, Echo } }}} == Small server Example == {{{ require 'eventmachine' module EchoServer def post_init puts "-- someone connected to the echo server!" end def receive_data data send_data ">>>you sent: #{data}" end end EventMachine::run { EventMachine::start_server "127.0.0.1", 8081, EchoServer puts 'running echo server on 8081' } }}} == Safe run in any circumstances == '''N.B.''' this is no longer required for a lot of apps, as of EM 0.12 you can now stack run blocks, i.e. {{{ EM::run{ EM::run {} } }}} does not raise. For threaded apps there may still be some requirement, however a good pattern for managable code is to push the call to {{{ #run }}} to the top of your application stack, and do your threaded work using {{{ EM::defer }}} where possible. {{{ #!ruby module EventMachine def EventMachine::safe_run(background = nil, &block) if EM::reactor_running? # Attention: here we loose the ability to catch # immediate connection errors. EM::next_tick(&block) sleep unless background # this blocks the thread as it was inside a reactor else if background $em_reactor_thread = Thread.new do EM::run(&block) end else EM::run(&block) end end end end }}} Usage: {{{ #!ruby EM::safe_run(:background) do EM::start_server(host, port, server_klass) EM::connect(host, port, client_klass) end }}} Use this snippet if you'd like to design your library in a way compatible with different apps: both event-driven and threaded. == Writing out to clients before Exit == Let connections finish their work before stopping EM for good. {{{ #!ruby class Server attr_accessor :connections def initialize @connections = [] # ... end def start @signature = EventMachine.start_server('0.0.0.0', 3000, Connection) do |con| con.server = self end end def stop EventMachine.stop_server(@signature) unless wait_for_connections_and_stop # Still some connections running, schedule a check later EventMachine.add_periodic_timer(1) { wait_for_connections_and_stop } end end def wait_for_connections_and_stop if @connections.empty? EventMachine.stop true else puts "Waiting for #{@connections.size} connection(s) to finish ..." false end end end class Connection attr_accessor :server # ... def unbind server.connections.delete(self) end end }}} == Start a server on an unassigned port == {{{ require ‘socket’ EM.run { srvr = EM.start_server “0.0.0.0”, 0 p Socket.unpack_sockaddr_in( EM.get_sockname( srvr )) } }}} == determine client's port == http://allgems.ruby-forum.com/gems/doc/eventmachine/0.12.8/classes/EventMachine/Connection.html#M000192 == More complicated example == {{{ class Echo < EventMachine::Connection def initialize(*args) super # stuff here... end def receive_data(data) p data send_data data close_connection_after_writing end def unbind p ' connection totally closed' end end EventMachine::connect '127.0.0.1', 22, Echo {|conn| } }}} == EventMachine over a Serial Port == It is actually possible to use Guilliame Perionnet's [http://rubyforge.org/projects/ruby-serialport/ ruby-serialport] library with (the pure Ruby) EventMachine. The following code works with EventMachine 0.12.2 and ruby-serialport 0.7.0: {{{ $eventmachine_library = :pure_ruby # need to force pure ruby require 'eventmachine' gem_original_require 'serialport' require 'smsrelay/gsmpdu' module EventMachine class EvmaSerialPort < StreamObject def self.open(dev, baud, databits, stopbits, parity) io = SerialPort.new(dev, baud, databits, stopbits, parity) return(EvmaSerialPort.new(io)) end def initialize(io) super end ## # Monkeypatched version of EventMachine::StreamObject#eventable_read so # that EOFErrors from the SerialPort object (which the ruby-serialport # library uses to signal the fact that there is no more data available # for reading) do not cause the connection to unbind. def eventable_read @last_activity = Reactor.instance.current_loop_time begin if io.respond_to?(:read_nonblock) 10.times { data = io.read_nonblock(4096) EventMachine::event_callback uuid, ConnectionData, data } else data = io.sysread(4096) EventMachine::event_callback uuid, ConnectionData, data end rescue Errno::EAGAIN, Errno::EWOULDBLOCK, EOFError # no-op rescue Errno::ECONNRESET, Errno::ECONNREFUSED @close_scheduled = true EventMachine::event_callback uuid, ConnectionUnbound, nil end end end class << self def connect_serial(dev, baud, databits, stopbits, parity) EvmaSerialPort.open(dev, baud, databits, stopbits, parity).uuid end end def EventMachine::open_serial(dev, baud, databits, stopbits, parity, handler=nil) klass = if (handler and handler.is_a?(Class)) handler else Class.new( Connection ) {handler and include handler} end s = connect_serial(dev, baud, databits, stopbits, parity) c = klass.new s @conns[s] = c block_given? and yield c c end class Connection # This seems to be necessary with EventMachine 0.12.x def associate_callback_target(sig) return(nil) end end end }}}