Servers, Threads, and the Ruby Way -- Architecture Question

Hi there, I'm a TOTAL Ruby newbie, but not new to programming.

I'm currently trying to program something I have no experience in ANY
language, much less Ruby, so it is getting a little bit out of hand,
also because I *think* I have some ideas of how I'd do it in C, or C#
maybe, but not so sure how to do it "the Ruby way". Add to it that I've
never really dealt with these sorts of things before (servers and
threads), which is making things hard and has me here looking for
advice.

Basically, I want to write a little *something* (program? server?
daemon? service? what's the difference?) that runs on a host (a public
one like bluehost, maybe) and accepts connections on two separate ports.

Now here's where it gets tricky. This *something* is a kind of game
server, which basically can run several games concurrently. Each game
has a list of users that can play that particular instance of a game.

So for instance this program runs n games and game 1 has k users, game 2
has j users, and so on.

Now, this server has to accept a remote connection that gives it the
parameters of the game (on one port)--like the list of users allowed to
play that game--- and accepts users connections to join game n (on
another port).

So I made a server with two threads, one to accept game configurations
and another to accept users. So far so good.

But now my question is: I want to have each game to run as a separate
thread, because each game is independent, right? So can a thread spawn
more threads? And doesn't this get a bit unwieldly?

Is there a better way to set this up? How do I write a *something* that
runs n games simultaneously, and that accepts two types of connections,
and when a user "joins", it somehow gets sent to the appropriate game
thread? Is there a way to pass messages between threads?

Architecture ideas?

Thanks,

-E.

···

--
Posted via http://www.ruby-forum.com/.

EP PG wrote in post #1036583:

Hi there, I'm a TOTAL Ruby newbie, but not new to programming.

[snipped, it is long!]

Architecture ideas?

OK., I thought of something. Please let me know if it sounds ridiculous.

I will have 2 processes. ONe is the "server" process which listens on
two ports via two threads like I already have. The other process is one
that basically creates a thread for each "game" that gets added to the
queue. Does this sound reasonable?

Let me know.

Now I only need to find out how to send data from the server process to
the schedule process. How is this typically done?

Thanks,

-E.

···

--
Posted via http://www.ruby-forum.com/\.

You might be interested in checking out my library Celluloid:

Celluloid is a library for making concurrent objects that each run in their
own thread. It lets you model things like the server processes/threads as
concurrent objects, along with each of the games.

Here's an example of building a TCP server with Celluloid:

https://github.com/tarcieri/celluloid/blob/master/lib/celluloid/tcp_server.rb

Celluloid would let you model the game threads like this:

class Game
  include Celluloid

  ...
end

Communication is handled through normal Ruby method calls. Celluloid also
supports asynchronous method calls which allows concurrent objects to send
a message requesting a call without waiting for a response.

···

On Tue, Dec 13, 2011 at 12:47 PM, EP PG <epasquali@hotmail.com> wrote:

EP PG wrote in post #1036583:
> Hi there, I'm a TOTAL Ruby newbie, but not new to programming.

[snipped, it is long!]

>
> Architecture ideas?
>

OK., I thought of something. Please let me know if it sounds ridiculous.

I will have 2 processes. ONe is the "server" process which listens on
two ports via two threads like I already have. The other process is one
that basically creates a thread for each "game" that gets added to the
queue. Does this sound reasonable?

Let me know.

Now I only need to find out how to send data from the server process to
the schedule process. How is this typically done?

Thanks,

-E.

--
Posted via http://www.ruby-forum.com/\.

--
Tony Arcieri

You do not need two processes. One process with multiple threads is
much easier. If game actions only occur for messages received from
clients you could to this:

- two listening threads (one per port obviously; if you want to get
fancy you can use a single thread with select())
- each listener spawns a reader thread per client
- if the game is multiplayer, you need 1 shared instance per game - if
not you want to have one instance per user
- logic is done inside reader threads which must hold a lock on the
game state (because it is shared)
- if you need to process messages per client asynchronously (i.e.
receive the next message while the previous one is processed, you can
use an additional thread per client)

If games have activities of their own (i.e. things happening after
fixed time or such) you need additional threads (one or more) per
game.

Another option might be event machine.

http://rubyeventmachine.com/

Kind regards

rober

···

On Tue, Dec 13, 2011 at 9:47 PM, EP PG <epasquali@hotmail.com> wrote:

EP PG wrote in post #1036583:

Hi there, I'm a TOTAL Ruby newbie, but not new to programming.

[snipped, it is long!]

Architecture ideas?

OK., I thought of something. Please let me know if it sounds ridiculous.

I will have 2 processes. ONe is the "server" process which listens on
two ports via two threads like I already have. The other process is one
that basically creates a thread for each "game" that gets added to the
queue. Does this sound reasonable?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote in post #1036718:

two ports via two threads like I already have. The other process is one
that basically creates a thread for each "game" that gets added to the
queue. Does this sound reasonable?

You do not need two processes. One process with multiple threads is
much easier. If game actions only occur for messages received from
clients you could to this:

- two listening threads (one per port obviously; if you want to get
fancy you can use a single thread with select())
- each listener spawns a reader thread per client
- if the game is multiplayer, you need 1 shared instance per game - if
not you want to have one instance per user
- logic is done inside reader threads which must hold a lock on the
game state (because it is shared)
- if you need to process messages per client asynchronously (i.e.
receive the next message while the previous one is processed, you can
use an additional thread per client)

If games have activities of their own (i.e. things happening after
fixed time or such) you need additional threads (one or more) per
game.

Another option might be event machine.
http://20bits.com/articles/an-eventmachine-tutorial/
http://rubyeventmachine.com/

Kind regards

rober

Hi, thanks, after reading around the web and thinking about it I can see
what you're saying and it makes sense. I've also decided that I won't
run the games as a thread, but simply as a record on the database which
contains the game "state" (the game runs slowly so I don't need to
update it too often). That way when I get a user connection all I need
to do is check to see if the user's move is "legal" and then update the
game state in the database if it is. So I only really need the two
threads for the two connections (from user and game creation command)
and that's it (well, plus the threads that do the connecting to the
database, and the rules checking I guess).

So yes, there are n games (records in the database) and each game has j
players (users authorized to modify the state in the nth game). The
server runs many games and listens to connections from many users. When
a user connects, "something" (as separate thread?) sees what game that
user is assigned to and reads the user's move. It then checks the user's
move to see if it's legal and if it is, it modifies the game's state
according to the move. Ideally, I should be able to handle several moves
(from different users) simultaneously and handle accesses to different
parts of the database (i.e. different games) by different users
simultaneously.

I was also looking into EventMachine after doing some thinking and
reading and thought it could be useful in case several users wanted to
access the database at the same time (for say, different games). But I
didn't quite understand the tutorials and couldn't quite figure out how
to set up the two listening ports, plus the database accesses (different
for each client/user connection) at the same time and without the
database accesses blocking things. I guess I need to do more reading.

@Tony Arcieri: How is Celluloid different from EventMachine? And when
would I use one vs the other?

Thanks and I apologize again for my newbie questions.

···

On Tue, Dec 13, 2011 at 9:47 PM, EP PG <epasquali@hotmail.com> wrote:

--
Posted via http://www.ruby-forum.com/\.