Server on Ruby

Hello, all!

I have joined to this mailing list just now, and I am
newbie in Ruby. So, sorry, if my question seemed as very
easy, but I can not solve it. Please help me, if possible.

Before Ruby I have programmed on Perl, but in some reasons
I was have to go to the Ruby. And I have to write a socket
server on Ruby. Because I have some examples on Perl, I
decided to translate it to Ruby for meeting, how it can be
done on Ruby.

So, I have a simply echo socket server on Perl:

···

#!/usr/bin/perl -wT
require 5.002;
use strict;
use IO::Socket;
use IO::Select;

create a socket to listen to a port

my $listen = IO::Socket::INET->new(Proto => ‘tcp’,
LocalPort => 2324,
Listen => 1,
Reuse => 1) or die $!;

to start with, $select contains only the socket we’re

listening on
my $select = IO::Select->new($listen);

my @ready;

wait until there’s something to do

while(@ready = $select->can_read) {

my $socket;

# handle each socket that's ready
for $socket (@ready) {

# if the listening socket is ready, accept a new

connection
if($socket == $listen) {
my $new = $listen->accept;
$select->add($new);
print $new->fileno . “: connected\n”;
} else {

    # otherwise, read a line of text and send it back

again
my $line="";
$socket->recv($line,80);
$line ne “” and $socket->send($line) or do {

	# either can't send or can't receive, so they must have

hung up
print $socket->fileno . “: disconnected\n”;
$select->remove($socket);
$socket->close;
};
}
}
}


I tryed to translate it into Ruby, but I did not find in
Ruby any objects as Perl IO::Select, so
how I can handle multiple clients on Ruby as Perl do it
with IO::Select?

May be there are some any additional documentation about
writing socket servers on Ruby?

Please, help me.

Best regards,
Alexandr Vladykin
moscower@smtp.ru

Received: Sat, 20 Mar 2004 04:06:50 +0900
And lo, Alexandr wrote:

So, I have a simply echo socket server on Perl:


#!/usr/bin/perl -wT
require 5.002;
use strict;
use IO::Socket;
use IO::Select;

create a socket to listen to a port

my $listen = IO::Socket::INET->new(Proto => ‘tcp’,
LocalPort => 2324,
Listen => 1,
Reuse => 1) or die $!;

to start with, $select contains only the socket we’re

listening on
my $select = IO::Select->new($listen);

my @ready;

wait until there’s something to do

while(@ready = $select->can_read) {

my $socket;

# handle each socket that's ready
for $socket (@ready) {

if the listening socket is ready, accept a new

connection
if($socket == $listen) {
my $new = $listen->accept;
$select->add($new);
print $new->fileno . “: connected\n”;
} else {

  # otherwise, read a line of text and send it back

again
my $line=“”;
$socket->recv($line,80);
$line ne “” and $socket->send($line) or do {

  # either can't send or can't receive, so they must have

hung up
print $socket->fileno . “: disconnected\n”;
$select->remove($socket);
$socket->close;
};
}
}
}

If you’re insistent on needint select() functionality, use
IO::select(readarray,[writearray, [errorarray, [timeout]]])

For your purpose, I’d use something like this:

···

PORT=2324

require ‘socket’
require ‘thread’

A function called for each socket

def handle_incoming(sock)

Threads are easy - lets put each incoming socket in

Its own thread. =).

Thread.new {

# Socket.addr -> [networkdomain, port, name, ip]
puts "New connection from #{sock.addr[2]} (#{sock.addr[3]})"

# Echo each line we get back to the socket.
# When the socket gets an error or is closed,
# gets returns nil, so the while loop exits.
while (line = sock.gets)
  sock.puts line
end

puts "Connection from #{sock.addr[2]} closed."

}
end

Create a new listener that listens on all addresses

and the port number in constant PORT (defined above)

TCPServer.new(local_address,port)

listener = TCPServer.new(‘’,PORT)

listener.accept returns sockets of new connections.

This while loop calls handle_incoming on each new

socket created. Doing it this way instead of putting

the Thread.new { … } code inside this while loop

bypasses ickiness with local variables being shared.

while (new_socket = listener.accept)
handle_incoming(new_socket)
end


It runs each socket in its own Ruby thread (Not to be confused with system threads), and network threads do not hang the interpreter when there are other threads to run.

Hope that helps.

  • Greg Millam

Alexandr Vladykin wrote:

Before Ruby I have programmed on Perl, but in some reasons
I was have to go to the Ruby. And I have to write a socket
server on Ruby. Because I have some examples on Perl, I
decided to translate it to Ruby for meeting, how it can be
done on Ruby.

Writing a server is pretty easy:

···

=======
require ‘socket’

server = TCPserver.open(2000)

while conn = server.accept
conn.puts Time.now.to_s
conn.shutdown
end

Or if you want to use threads:

=======
require ‘socket’

server = TCPserver.open(2000)

while 1
Thread.start(server.accept) do |conn|
conn.puts “hello”
# do something
conn.shutdown
end
end

I tryed to translate it into Ruby, but I did not find in
Ruby any objects as Perl IO::Select, so
how I can handle multiple clients on Ruby as Perl do it
with IO::Select?

I’d say… with IO.select :slight_smile:
or Kernel.select
you should install ri (ruby information tool) :wink:

IO.select(…)

IO.select( readArray [, writeArray [errorArray [timeout]]] ) →
anArray
or nil

Kernel.select(…)

select( readArray [, writeArray [errorArray [timeout]]] ) → anArray
or nil

Performs a low-level select call, which waits for data to become

available from input/output devices. The first three parameters are
arrays of IO objects or nil. The last is a timeout in seconds, which
should be an Integer or a Float. The call waits for data to become
available for any of the IO objects in readArray, for buffers to have
cleared sufficiently to enable writing to any of the devices in
writeArray, or for an error to occur on the devices in errorArray. If
one or more of these conditions are met, the call returns a
three-element array containing arrays of the IO objects that were
ready. Otherwise, if there is no change in status for timeout seconds,
the call returns nil. If all parameters are nil, the current thread
sleeps forever.

select( [$stdin], nil, nil, 1.5 ) #=> [[#IO:0x401b9460], , ]

May be there are some any additional documentation about
writing socket servers on Ruby?

try the Programming Ruby book (AKA the pickaxe)

···

il Sat, 20 Mar 2004 04:06:50 +0900, “Alexandr Vladykin” moscower@smtp.ru ha scritto::

Note that select() only blocks the current thread, so if you have
multiple threads, and select() in one of them, only that thread will
block.

···

gabriele renzi (surrender_it@rc1.vip.ukl.yahoo.com) wrote:

select( readArray [, writeArray [errorArray [timeout]]] ) → anArray
or nil

Performs a low-level select call, which waits for data to become

available from input/output devices. The first three parameters are
arrays of IO objects or nil. The last is a timeout in seconds, which
should be an Integer or a Float. The call waits for data to become
available for any of the IO objects in readArray, for buffers to have
cleared sufficiently to enable writing to any of the devices in
writeArray, or for an error to occur on the devices in errorArray. If
one or more of these conditions are met, the call returns a
three-element array containing arrays of the IO objects that were
ready. Otherwise, if there is no change in status for timeout seconds,
the call returns nil. If all parameters are nil, the current thread
sleeps forever.


Eric Hodel - drbrain@segment7.net - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

“gabriele renzi” surrender_it@remove.yahoo.it schrieb im Newsbeitrag
news:aiim50hrrofuc2ftcq0drhpd5v9b3ho3c2@4ax.com

···

il Sat, 20 Mar 2004 04:06:50 +0900, “Alexandr Vladykin” > moscower@smtp.ru ha scritto::

May be there are some any additional documentation about
writing socket servers on Ruby?

try the Programming Ruby book (AKA the pickaxe)

… which you can find online here:

http://www.rubycentral.com/book/

and here (with 1.8 change comments):
http://phrogz.net/ProgrammingRuby/

Have fun

robert