Hello,

On 18 Ϧ 2012, at 09:04 , Carlo E. Prelz <fluido / fluido.as> wrote:

> 	Subject: Advice for simple client/server application
> 	Date: Sun 18 Nov 12 06:09:42AM +0900
> 
> Quoting Panagiotis Atmatzidis (atma / convalesco.org):
> 
>> I need to write a client/server application and I'd like to some
>> advice from more experienced users.  
>> 
>> There will be multiple clients and one server. Every client should
>> automatically identify to the server and give some details
>> (client_id, date, time, etc). The identification needs to be at very
>> basic level, just to avoid *strange things* from happening, since
>> the server is going to listen on the internet (firewall rules will
>> be applied, but some clients may have dynamic ip's, so some subnets
>> might be able to connect).  
>> 
>> The server will dig for data from a database, at each client's
>> request will send an array (list of words) to the client. Then the
>> server will receive a hash with detailed info from the client about
>> the each element of the array and will dump the results into the
>> database. These arrays will be formed only when requested by
>> clients. The server will make sure clients don't get the same arrays
>> and make a check to the given results and that's about it. 
>> 
>> It's a fairly simple application. I was thinking of using sinatra +
>> routes, to create the list in 'txt' format to the client but I'm not
>> sure how to send the results back to the sinatra server yet. 
>> 
>> So I'd like to ask more advanced users if there's any protocol, gem
>> and/or framework that would make this task easier since I've never
>> done anything similar before. I know there's a variety of protocols
>> which can be used. I'd like to keep things simple & clean as much as
>> possible. 
> 
> You do not specify if the clients are also written in Ruby. When I
> have to do inter-process communications, on the same machine or
> between remote machines, I use DRb (Distributed Ruby), which is
> included in MRI. I certainly had to pour some sweat to gain confidence
> with it, but it was worth the effort. You can even set it up to use
> SSL, so the traffic will be encrypted.
> 
> Let's say you have a server based on this scaffold (engine.rb):
> 
> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
> require 'drb/drb'
> require 'drb/ssl'
> 
> class Engine
>  HOST='yourhost.xxx'
>  PORT=21212
>  URI="drbssl://#{HOST}:#{PORT}"
>  CERTNAME=[['C',HOST.split('.')[-1]],['O',HOST],['CN',self.to_s]]
> 
>  def initialize
>    config={:verbose=>false,:SSLCertName=>CERTNAME}
>    @srv=DRb::start_service(URI,self,config)
> 
>    #
>    # Your inits
>    #
> 
>    @para1=rand(1000)
>    @para2=rand(1000)
>  end
> 
>  def runme
>    DRb::thread.join()
>  end
> 
>  #
>  # Remote-callable methdos
>  #
> 
>  def method1(a)
>    "#{@para1} #{@para2} method 1 returns #{a.to_s}"
>  end
> 
>  def method2(a)
>    "#{@para1} #{@para2} method 2 returns #{a.to_s} #{a.to_s}"
>  end
> 
>  def Engine::remote
>    config={:verbose=>false}
> 
>    DRb.start_service(nil,nil,config)
>    DRbObject.new(nil,URI)
>  end
> end
> 
> if($0==__FILE__)
>  Engine::new.runme
> end
> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
> 
> Your client may be something like this:
> 
> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
> require 'engine.rb'
> 
> class Client
>  def initialize
>    @engine=Engine::remote
>  end
> 
>  def runme
>    puts @engine.method1(rand(1000))
>    puts @engine.method1('test')
>    puts @engine.method2(rand(1000))
>    puts @engine.method2('test')
>  end
> end
> 
> Client::new.runme
> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
> 
> Your engine can provide an identify method (you may have a hash of
> user ids/passwords associated to one or more address, for
> example). Then, you would have a 'dig' method that would provide the
> desired list of words.
> 
> For me, DRb has cut the cake several times (you can also base it on
> Unix sockets, for intra-machine communications). 
> 
> There are some snags. The biggest is that methods of the DRb-exported
> objects are executed remotely, but if your client receives remote
> objects, it will receive LOCAL COPIES of them. Let's say your engine
> has object @ob, which has method meth. If your engine has this method
> 
> def m
>  @ob.meth
> end	
> 
> meth is executed remotely, by the engine process. But if your
> methods just returns @ob:
> 
> def m
>  @ob
> end	
> 
> and in your client you have
> 
> ob=@engine.m
> ob.meth
> 
> meth is executed in the client's thread (and thus, for example, it
> won't be able to access the database opened by the remote engine).
> 
> I hope this is of help.
> 
> Carlo
> 
> -- 
>  *         Se la Strada e la sua Virtu' non fossero state messe da parte,
> * K * Carlo E. Prelz - fluido / fluido.as             che bisogno ci sarebbe
>  *               di parlare tanto di amore e di rettitudine? (Chuang-Tzu)
> 



Thanks for code sample and the extensive answer Carlo! 

So from what I understand, druby opens a connection and keeps it alive until the client ends execution right?

This approach could be a solution, thanks :-)

Panagiotis (atmosx) Atmatzidis

email:	atma / convalesco.org
URL:	http://www.convalesco.org
GnuPG ID: 0xE736C6A0
gpg --keyserver x-hkp://pgp.mit.edu --recv-keys 0xE736C6A0
--
The wise man said: "Never argue with an idiot. They bring you down to their level and beat you with experience."