From: Brian Candler Date: 2002-12-14T08:46:39+09:00 Subject: Re: TCP Server On Sat, Dec 14, 2002 at 12:20:29AM +0900, Shannon Fang wrote: > 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) @session = session end def run @session.print "+OK I am a fake POP3 server\n" while line = @session.gets case line when /quit/i break else @session.print "-ERR I don't understand #{line}" end end @session.print "+OK bye\n" @session.close 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.