📜 ⬆️ ⬇️

Ruby and EventMachine

So, EventMachine is a fast and easy framework for networking in Ruby . EventMachine uses an event-oriented (asynchronous) mechanism for handling network connections. (The differences between synchronous and asynchronous models of processing network connections are covered in a lot of information on the network).
Since, in the Russian-language Internet is very scarce information on this wonderful gem'u spread this article.

Setting a standard enough for a Ruby programmer:
gem install eventmachine

Let's start with an example from the documentation (somewhat modified):

require 'rubygems' require 'eventmachine' class EchoServer < EventMachine::Connection def post_init puts "  " end def receive_data data send_data ">>> #{data}" close_connection if data =~ /quit/i end def unbind puts " " end end EventMachine::run { EventMachine::start_server '', 8081, EchoServer } 

Now we will analyze in order (the reverse - it will be more convenient):

EventMachine :: run - initializes and starts the message processing loop ( EventReactor ), it returns from this function only when the stop_event_loop method is called . The method can (and should) be passed a block that runs before the start of the message processing cycle. For example, we can initialize a server here, configure timers, establish a client connection, etc. In this example, we start the echo server, for this is the method (module method EventMachine ) EventMachine :: start_server , its parameters are the IP address and port for listening, in our example the IP is empty so that you can connect from any host. The next and probably most important parameter is the connection handler — for example, the name of a class (a subclass of EventMachine :: Connection ) or a module (in this case, the module is mixed into an anonymous subclass of EventMachine :: Connection ). In this example, this is the EchoServer class.
For each connection to the server, an object of the EchoServer class is initiated !!!
In the message processing loop ( EventReactor ), messages are initiated — in this context, these are calls to the methods of an object of the EchoServer class. The main messages are:

In the above example, after the connection with the client is established, the message “Connection to the server” is displayed, if the connection is closed, the connection is closed. When a message is received, it is sent back using the send_data method (to send a message); if a quit message is received, the connection is closed.
For more information about class methods, see the documentation.

Everything is almost the same with a client - examples can be found on the Internet, including in Russian.
In general, the easiest way is to test using telnet:
telnet localhost 11777

We will consider more interesting topics.
I already met on Habré a chat made using EventMachine , however all its goodies were not used there. Now we will write a simple chat (I will not lie, but I think that it will withstand 1000 connections, if you correct the code a little, as a hint - the EventMachine.defer method).

Consider the channels EventMachine :: Channel . This mechanism is not new at all and is used in various systems; moreover, it is a whole pattern. The mechanism is the following: there is a channel (well, let's say a long corridor of the floor of an office building), and there are subscribers (those who opened the doors to hear everything that happens in the corridor). Anyone, not even a subscriber (the one who did not open the door) can send a message to the channel (shout anything into the corridor) and all subscribers will receive (hear) it. You can unsubscribe from the channel (close the door).

So, the channel has three methods: subscribe (subscribe), push (send message), unsubscribe (unsubscribe). Below is the implementation of the chat (with one channel - room)

 require 'rubygems' require 'eventmachine' require 'socket' class User < EventMachine::Connection @@room = EventMachine::Channel.new attr_reader :port, :ip, :sid def receive_data data @@room.push("#{ip}:#{port} >>> #{data}") close_connection if data =~ /quit/i end def unbind str = " #{ip}:#{port}\n" @@room.push(str) puts str @@room.unsubscribe(sid) end def post_init @port, @ip = Socket.unpack_sockaddr_in(get_peername) str = "  #{ip}:#{port}\n" @sid = @@room.subscribe { |msg| send_data msg } @@room.push(str) puts str end end EventMachine::run { EventMachine::start_server '', 11777, User } 

In general, programming with EventMachine is somewhat more complicated than usual. This is due to asynchrony, the use of a large number of blocks, procedures and other things. In the examples above, this is almost invisible , but if you want to use EventMachine you will have to face it.

Source: https://habr.com/ru/post/106809/

All Articles