TCP Server 
Author Message
 TCP Server

Hi,

I am learning how to use Ruby to write a TCP Server. I used the sample code
in PickAxe, it worked fine, but I have no idea how I can let the program
connect more than one client? Do I need to use thread?

Can anyone show me how to do this by writing a echo server which can connect
multiple clients? And is there events like "on_connect" "on_disconnect"
available in ruby?

Thanks a lot.
Shannon

_________________________________________________________________
MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*.
http://www.*-*-*.com/



Tue, 31 May 2005 23:20:29 GMT  
 TCP Server


Quote:
> Hi,

> I am learning how to use Ruby to write a TCP Server. I used the sample
code
> in PickAxe, it worked fine, but I have no idea how I can let the program
> connect more than one client? Do I need to use thread?

> Can anyone show me how to do this by writing a echo server which can
connect
> multiple clients? And is there events like "on_connect" "on_disconnect"
> available in ruby?

Take a look at

GServer.zip   A generic, multi-threaded e-service server in Ruby. Includes a
simplistic HttpEchoServer.rb to demonstrate how to write your own server.

http://www.rogare.com/index.php?inc=downloads/ruby/ruby

Mikkel



Tue, 31 May 2005 23:28:37 GMT  
 TCP Server

S> I am learning how to use Ruby to write a TCP Server. I used the sample code
S> in PickAxe, it worked fine, but I have no idea how I can let the program
S> connect more than one client? Do I need to use thread?

 You have an example at

   http://www.ruby-lang.org/en/man-1.4/socket.html#TCPServer

Guy Decoux



Tue, 31 May 2005 23:26:07 GMT  
 TCP Server

| Hi,
|
| I am learning how to use Ruby to write a TCP Server. I used the sample code
| in PickAxe, it worked fine, but I have no idea how I can let the program
| connect more than one client? Do I need to use thread?
|
| Can anyone show me how to do this by writing a echo server which can
| connect multiple clients? And is there events like "on_connect"
| "on_disconnect" available in ruby?
|
| Thanks a lot.
| Shannon
|
| _________________________________________________________________
| MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*.
| http://join.msn.com/?page=features/virus

Shannon,

Fork (Kernel.fork), thread(Thread), or poll (see below).

If you have linux (or other unices, even), you might want to check out Michael
Granger's excellent Ruby-Poll library
(http://www.deveiate.org/code/Ruby-Poll.shtml) which includes a nice little
chatserver example (you also might want to check out MUES, but just b/c it
plainly rocks).

TCPServer (socket programming in general, actually) is a subject that comes up
pretty regularly; you should be able to find some additional examples via
Google.

~ Bruce

--
Bruce R. Williams :: [iusris/#ruby-lang] :: http://www.codedbliss.com

  'It does not require a majority to prevail, but rather an irate,
  tireless minority keen to set brush fires in people's minds.'
  -- Samuel Adams



Tue, 31 May 2005 23:36:16 GMT  
 TCP Server
Hi,

Thanks all.

Quote:
>Fork (Kernel.fork), thread(Thread), or poll (see below).

I regret that I'm using Windows 2000. So I can't use Fork?
I don't know if poll is only for Unix or platform independent?

My question here is: which one can offer best performance? use thread or not
use thread?

Thanks
Shannon

_________________________________________________________________
MSN 8 helps eliminate e-mail viruses. Get 2 months FREE*.
http://join.msn.com/?page=features/virus



Tue, 31 May 2005 23:45:53 GMT  
 TCP Server
Hi,

I just found an example in talk archive about using thread with tcp server.
If anyone have a solution that does not use thread, please tell me,
otherwise, please accept my apology that I should check the talk-archive
first... :p

Thanks
Shannon

_________________________________________________________________
Protect your PC - get McAfee.com VirusScan Online
http://clinic.mcafee.com/clinic/ibuy/campaign.asp?cid=3963



Tue, 31 May 2005 23:49:33 GMT  
 TCP Server
Hi Shannon,

Quote:
> I just found an example in talk archive about using thread with tcp server.
> If anyone have a solution that does not use thread, please tell me,
> otherwise, please accept my apology that I should check the talk-archive
> first... :p

I prefer to use select() than threads, for a couple reasons, in Ruby.
My sense is that, since the whole process is blocked (all your threads)
if one of your IO calls stalls (in any thread), then you have to find
a way to do non-blocking IO whether you're using threads or not.  And I
personally find select() to be sufficient to the task without bothering
with threads.  (It may just be personal opinion, or preference. :)

If it helps, here's a snippet from a TCP-based chat-like server I
wrote recently.  I've tried to delete the parts of the code that are
relevant only to my specific application.  Thus the code below is
untested, but is drawn from working code (for whatever that's worth
<grin>.)

  def accept_and_process_clients(timeout)
    begin
      # This select call is the key to the whole operation.  In my program,
      # I only care which clients are ready to be read from (or whether the
      # server socket is ready to accept a new connection from a client.)
      # You'll notice I pass in 'nil' for asking which sockets are ready
      # to be written to.  In my case, when I have something to write to
      # a socket, I can get away with just doing a blocking write, because
      # for my purposes it's fast enough.  You may or may not actually want
      # to check which sockets are "ready" to be written to, to avoid any
      # blocking at all in your writes.

      if ios
        # disconnect any clients with errors
        ios[2].each {|sock| ios[0].delete(sock); disconnect_client(sock, false) }
        # accept new clients or process existing client input
        ios[0].each do |sock|

            accept_client(sock)
          else
            process_client_input(sock)  # whatever this means in your app.
          end
        end
      end
    rescue IOError, SystemCallError
    end
  end

  def accept_client(sock)
    client = sock.accept
    if client
      begin
        # Initialize client however makes sense in your application.
        # In my case I extend the client socket with some extra
        # features from a login-session/terminal-server module.
        # I also get the client's IP and Port numbers from peeraddr,
        # which can throw exceptions if there's a problem, thus the
        # rescue clause below...
      rescue IOError, SystemCallError
        client.close
      else

      end
    end
  end

  def disconnect_client(client)

    client.close
  end

  def run


    begin
      loop {
        # I do other periodic tasks in the loop besides accept and
        # respond to clients - so I have a slightly more complicated
        # way of keeping track of the timeout/next-update interval
        # which I've deleted in this example....
        timeout = WhateverYouNeed
        accept_and_process_clients(timeout)
      }
    rescue Interrupt, IRB::Abort, NoMemoryError, SystemExit => ex
      puts "Caught exception: #{ex.inspect} at #{ex.backtrace[0]} - saving and shutting down..."
    rescue Exception => ex
      puts "Caught exception: #{ex.inspect} at #{ex.backtrace[0]} - ignoring and continuing..."
      sleep 1
      retry
    ensure
      disconnect_all_clients


    end
  end

For completeness, here's routines where I actually end up doing send &
recv on the client sockets.  They're part of a buffered terminal IO

  def terminal_buffered_read
    begin
      if Kernel.select([self], nil, nil, 0)
        dat = self.recv(65536)
        if !dat || dat.empty?

        else

        end
      end
    rescue IOError, SystemCallError

    end
  end

  def send_string(str)
    str = str.gsub(/\n/, "\r\n")
    begin
      while str.length > 0
        sent = self.send(str, 0)
        str = str[sent..-1]
      end
    rescue IOError, SystemCallError

    end
  end

If the recv returns EOF, *or* if something goes wrong with the

for my application.... You might want to handle errors differently.
(Note, again, that my send is a blocking-send.  But you can make yours
non-blocking using select() if you need to.)

Finally, I should mention that in theory, since Windows doesn't
support true non-blocking IO on its sockets (as far as I know)
that there is a possibility that the accept() call could block.
[Note, the above code, in the context of my application, has been
used without problem on Windows and Linux.]  The possibility for
accept() blocking happens when a client tries to connect, and
select() says "read me!", but the client hurriedly disconnects,
so that by the time we actually get to the accept(), the client
is gone, and thus the accept() call blocks until a new client
connects.  This has not yet happened in my application, but it

above condition, it would return the error EWOULDBLOCK instead
of blocking.

Again, however, in Ruby, using threads would not be a solution to
the above.  Because if accept() blocks, your whole process (all
your threads) are blocked.  So I'd suggest using threads only if
that model is more convenient to how your application processes
its data.  For mine, threads seemed like extra work.

Hope this helps,

Bill



Wed, 01 Jun 2005 01:37:18 GMT  
 TCP Server

Quote:
> > I just found an example in talk archive about using thread with tcp server.
> > If anyone have a solution that does not use thread, please tell me,
> > otherwise, please accept my apology that I should check the talk-archive
> > first... :p

> I prefer to use select() than threads, for a couple reasons, in Ruby.
> My sense is that, since the whole process is blocked (all your threads)
> if one of your IO calls stalls (in any thread), then you have to find
> a way to do non-blocking IO whether you're using threads or not.  And I
> personally find select() to be sufficient to the task without bothering
> with threads.  (It may just be personal opinion, or preference. :)

I prefer to use a combination of both select and threads,
I'm a bit thread-crazy though due to the extreme ease of thread-use in ruby :-)

class SimpleTCPServer
        def initialize(port, interface, max_users = 4, timeout = 10)



        end

        def handle_request( request )
                # perform the actual request, return nil if the client should be closed
        end

        def handle_user( socket )
                while not socket.closed?

                        unless a == nil
                                unless (b = handle_request( socket.readline.chop )) == nil
                                        socket.print b.to_s
                                else
                                        socket.end
                                end
                        else
                                socket.close
                        end
                end
        end

        def listen
                while (session = server.accept)

                                Thread.new{
                                        ref = session
                                        begin

                                                handle_user( ref )
                                        rescue IOError
                                        end

                                        ref.close unless ref.closed?

                                }
        end
end



Wed, 01 Jun 2005 03:20:23 GMT  
 TCP Server

Quote:

>I prefer to use select() than threads, for a couple reasons, in Ruby.
>My sense is that, since the whole process is blocked (all your threads)
>if one of your IO calls stalls (in any thread), then you have to find
>a way to do non-blocking IO whether you're using threads or not.  And I
>personally find select() to be sufficient to the task without bothering
>with threads.  (It may just be personal opinion, or preference. :)

I have not encountered such situation when using threads.

My application have a set of worker threads, which either serve a
client, waiting on a Mutex protecting accept(), or waiting at accept(),
so there is always one thread waiting on accept(), and the application
does not block.

I suppose Ruby does some tricks to overcome the blocking.

Idan.



Wed, 01 Jun 2005 03:43:04 GMT  
 TCP Server


Quote:

> >I prefer to use select() than threads, for a couple reasons, in Ruby.
> >My sense is that, since the whole process is blocked (all your threads)
> >if one of your IO calls stalls (in any thread), then you have to find
> >a way to do non-blocking IO whether you're using threads or not.  And I
> >personally find select() to be sufficient to the task without bothering
> >with threads.  (It may just be personal opinion, or preference. :)

> I have not encountered such situation when using threads.

> My application have a set of worker threads, which either serve a
> client, waiting on a Mutex protecting accept(), or waiting at accept(),
> so there is always one thread waiting on accept(), and the application
> does not block.

> I suppose Ruby does some tricks to overcome the blocking.

Whoa.  Interesting.  Well, my apologies if my post was incorrect.
I've read accounts on ruby-talk in the past of the whole process
(all Ruby-threads) being blocked during IO.  I had taken this to
mean this was the general case, rather than some specific exception
being discussed.

Hmm, it's nice when Ruby is smarter than me (seems to keep happening :)

In my particular application, avoiding threads still seems convenient,
as I can disregard reentrancy issues.

Thanks,

Bill



Wed, 01 Jun 2005 04:54:08 GMT  
 TCP Server

Quote:
----- Original Message -----


Sent: Friday, December 13, 2002 12:54 PM
Subject: Re: TCP Server



> > >I prefer to use select() than threads, for a couple reasons, in Ruby.
> > >My sense is that, since the whole process is blocked (all your threads)
> > >if one of your IO calls stalls (in any thread), then you have to find
> > >a way to do non-blocking IO whether you're using threads or not.  And I
> > >personally find select() to be sufficient to the task without bothering
> > >with threads.  (It may just be personal opinion, or preference. :)

> > I have not encountered such situation when using threads.

> > My application have a set of worker threads, which either serve a
> > client, waiting on a Mutex protecting accept(), or waiting at accept(),
> > so there is always one thread waiting on accept(), and the application
> > does not block.

> > I suppose Ruby does some tricks to overcome the blocking.

> Whoa.  Interesting.  Well, my apologies if my post was incorrect.
> I've read accounts on ruby-talk in the past of the whole process
> (all Ruby-threads) being blocked during IO.  I had taken this to

What might be ment is that when you write your own C extention and you call
a C function from Ruby, all Ruby threads are blocked until the function
returns. So if you block on IO operation (say, calling read()) in that
function, no Ruby threads will have a chance to execute. However if you do
IO via pure Ruby API, everything works fine (threads are not blocked).

- Show quoted text -

Quote:
> mean this was the general case, rather than some specific exception
> being discussed.

> Hmm, it's nice when Ruby is smarter than me (seems to keep happening :)

> In my particular application, avoiding threads still seems convenient,
> as I can disregard reentrancy issues.

> Thanks,

> Bill



Wed, 01 Jun 2005 05:08:48 GMT  
 TCP Server

Quote:

> I am learning how to use Ruby to write a TCP Server. I used the sample code
> in PickAxe, it worked fine, but I have no idea how I can let the program
> connect more than one client? Do I need to use thread?

> Can anyone show me how to do this by writing a echo server which can
> connect multiple clients?

In case it's any use, here are a few snippets of fake POP3 server I wrote a
while back.

Here was my first attempt: the POP3 server instance is represented by its
own object.

-------------------------------------------------------------------------
#!/usr/local/bin/ruby -w

class Testserver
  def initialize(session)

  end
  def run


      case line
        when /quit/i
          break
        else

      end
    end


  end
end

require 'socket'
port = (ARGV[0] || 110).to_i
server = TCPServer.new('0.0.0.0', port)
while (session = server.accept)
  Thread.new do
    Testserver.new(session).run
  end
end
-------------------------------------------------------------------------

The messy thing with that is having to keep referencing the instance
variable for the TCPSocket every time you want to input or output.

I tried subclassing TCPSocket, but I couldn't work out how to convert the
TCPSocket returned by server.accept into an instance of the subclass.

In the end, the tidiest solution seemed to be to dynamically add a 'run'
method to each TCPSocket as it is created:

-------------------------------------------------------------------------
#!/usr/local/bin/ruby -w

module Pop3
  def run
    print "+OK I am a fake POP3 server\n"
    while line = gets
      case line
        when /quit/i
          break
        else
          print "-ERR I don't understand #{line}"
      end
    end
    print "+OK bye\n"
    close
  end
end

require 'socket'
port = (ARGV[0] || 110).to_i
server = TCPServer.new('0.0.0.0', port)
while (session = server.accept)
  session.extend Pop3
  Thread.new do
    session.run
  end
end

-------------------------------------------------------------------------

It might not be quite as efficient though, although I don't know how much
overhead is associated with extending an object in this way.

Hope this gives you something to play with...

Regards,

Brian.



Wed, 01 Jun 2005 07:46:39 GMT  
 TCP Server
Hello Shannon,


SF> Can anyone show me how to do this by writing a echo server which can connect
SF> multiple clients? And is there events like "on_connect" "on_disconnect"
SF> available in ruby?

from ruby distribution :)

# socket example - server side using thread
# usage: ruby tsvr.rb

require "socket"

gs = TCPserver.open(0)
addr = gs.addr
addr.shift
printf("server is on %s\n", addr.join(":"))

while TRUE
  Thread.start(gs.accept) do |s|
    print(s, " is accepted\n")
    while s.gets
      s.write($_)
    end
    print(s, " is gone\n")
    s.close
  end
end

--
Best regards,



Thu, 02 Jun 2005 14:05:27 GMT  
 
 [ 13 post ] 

 Relevant Pages 

1. TCP server

2. forking tcp server.

3. PyAsync: An asynchronous TCP server module

4. TCP-Server daemon code strangeness

5. Simple TCP Server || Daemonize || Continuous

6. TCP Server under Tcl 8.0

7. Concurrent TCP-Servers

8. TCP Server sitting behind a proxy

9. Threading and TCP server

10. reliable tcp server holding multiple connections

11. TCP server with Tcl-dp ?

12. How do I read/write many matrices through TCP server?

 

 
Powered by phpBB® Forum Software