By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,961 Members | 1,301 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,961 IT Pros & Developers. It's quick & easy.

2-player game, client and server at localhost

P: n/a
hi, everyone.

I'm writing a 2-players game that should support network mode. I'm now
testing it on 1 PC since I don't have 2. I directly use sockets, and
both client and server do computations, the only data transfered is
user mouse/kbd input.

It works synchronously, but somehow, when I play in client window,
both client and server have 17 fps, while when playing in server
window, server has 44 fps while client has 5, and due to forced
synchronization, they both run very slowly (I wonder how come server
says it has 44fps?).

Does anybody have an idea how can this be? Not that users will test 2
game intances communicating via localhost, but I need to make it work
properly.

--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Jul 30 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
Michael Rybak wrote:
I'm writing a 2-players game that should support network mode. I'm now
testing it on 1 PC since I don't have 2. I directly use sockets, and
both client and server do computations, the only data transfered is
user mouse/kbd input.

It works synchronously, but somehow, when I play in client window,
both client and server have 17 fps, while when playing in server
window, server has 44 fps while client has 5, and due to forced
synchronization, they both run very slowly (I wonder how come server
says it has 44fps?).

Does anybody have an idea how can this be?


I'd suggest not spending time profiling, debugging, optimizing a
"home-brewed" implementation using sockets but switch to Twisted or Pyro
or something like that and save yourself a lot of headaches.

Chances are this will magically speed things up to acceptable levels, too.

-Peter
Jul 30 '05 #2

P: n/a
On Sat, 30 Jul 2005 19:36:52 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:

It works synchronously, but somehow, when I play in client window,
both client and server have 17 fps, while when playing in server
window, server has 44 fps while client has 5, and due to forced
synchronization, they both run very slowly (I wonder how come server
says it has 44fps?).
Well, for a 2 player game of this sort, I'd think there should
be one server and TWO clients... It sounds more like you have a
master-slave arrangement with the slave forced to synchronize to the
master.

If you are running on Windows, the program with the input focus
is probably running at a higher priority... So the "server", when having
input focus, gets to compute lots of stuff while the client gets less
CPU time... and if the client then (whenever it does a frame say) does a
transaction with the server, it may do nothing while waiting for the
server to respond.

When the "client" has the focus, the server may be processing at
lower priority, and the two only seem to match speed because the client
is blocked waiting for a response from the server (allowing the server
to run at full speed until it sends the response).
Does anybody have an idea how can this be? Not that users will test 2
game intances communicating via localhost, but I need to make it work
properly.
Define "work properly"... It sounds like they are working
properly /as coded/ and are being affected by OS priority schemes. I
say "as coded" since, as I mentioned in the first paragraph, it sounds
like you have your server doing double duty -- both as a client and as
the server for the second client. The server should not have ANY client
type interface (other than start-up and shut-down or debug override
commands). All frame-based rendering should be in the clients. I also
suspect that, with two clients and a server, you'd see the same behavior
-- the "non-input" client will be running at a lower priority, thereby
achieving a lower frame-rate.

It also sounds like your server is doing something like:

loop
if socket has data then
read socket
compute new state
send reply
end if
do nasty computation
end loop

This logic will suck up as much CPU time as the OS will give the
program... While if the client looks like

loop
send data to server
read reply (blocking)
do nasty computation
end loop

then it not only has to compete for CPU time, it does nothing while
waiting for the server to handle the section inside the IF block.

But what would happen if you put something like os.sleep(0.025)
inside the loops? Assuming the loop takes 0.025sec to process, the total
comes to 0.05 seconds (20fps) AND releases the CPU for the other process
to compute.

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Jul 30 '05 #3

P: n/a
Thank you very much for your response, and may I point out some details:
It works synchronously, but somehow, when I play in client window,
both client and server have 17 fps, while when playing in server
window, server has 44 fps while client has 5, and due to forced
synchronization, they both run very slowly (I wonder how come server
says it has 44fps?).
DLB> Well, for a 2 player game of this sort, I'd think there should
DLB> be one server and TWO clients... It sounds more like you have a
DLB> master-slave arrangement with the slave forced to synchronize to the
DLB> master.
Yes, that's what I have. I was already told I should have 1 server and
2 clients, well I will, but I'd really like to make it work the
master-slave way now.

DLB> If you are running on Windows,
Yes, I am

To answer the rest of your message: the "client" and "server" (C and S
below) are actually equal in my implementation. They both compute
everything. I was told it's not smart to do that, but I can't see why
is it better to have server compute everything: there are only 2
players, and there's quite not much computations, while transferring
current status is much more traffic-consuming than simply transferring
user motions.

Below I outline what S and C do:

S:
loop
draw screen
accept player1 input from mouse/kbd
send player1 input to C
process player1 input
hang till C sends us player2 input
process player2 input

do the nasty computations :)
end loop

C:
loop
draw screen
hang till S sends us player1 input
process player1 input
accept player2 input from mouse/kbd
send player2 input to S
process player2 input

do the nasty computations :)
end loop
So you see C and S should cause equal load of CPU.
By the way, yesterday a friend of mine kindly agreed to test the game
online with me, and my God I was so happy to see it DID connected and
we could play (yes, this is the first program in my 10+ years of
programming that sends something over the web), but the speed is
overwhelmingly dreadful, near 3 fps :), while my 1.2 Celeron said I
had 21 fps, and his 3.0 Pentium said he had 120.

He tends to think that my problem is that they both hang to wait for
the input of each other, and that happens after each frame is drawn.
Well, it is lame, but why does it work fine at my pc when client
window is active?

And another important note - he also tested 2 instances playing via
localhost at his PC, and they both indeed had 35 fps, no matter which
window was active. I believe he has hyperthreading turned on while I
don't, but I wonder home come it wouldn't work without it? I've looked
at my CPU load, and for C being active we have 45% for C/45% for S,
while for S being active - 88% for S/ 11% for C :((

I'd really welcome any suggestions, please.
DLB> the program with the input focus is probably running at a higher
DLB> priority... So the "server", when having input focus, gets to compute
DLB> lots of stuff while the client gets less CPU time... and if the
DLB> client then (whenever it does a frame say) does a transaction with
DLB> the server, it may do nothing while waiting for the
DLB> server to respond.

DLB> When the "client" has the focus, the server may be processing at
DLB> lower priority, and the two only seem to match speed because the client
DLB> is blocked waiting for a response from the server (allowing the server
DLB> to run at full speed until it sends the response).
Does anybody have an idea how can this be? Not that users will test 2
game intances communicating via localhost, but I need to make it work
properly.


DLB> Define "work properly"... It sounds like they are working
DLB> properly /as coded/ and are being affected by OS priority schemes. I
DLB> say "as coded" since, as I mentioned in the first paragraph, it sounds
DLB> like you have your server doing double duty -- both as a client and as
DLB> the server for the second client. The server should not have ANY client
DLB> type interface (other than start-up and shut-down or debug override
DLB> commands). All frame-based rendering should be in the clients. I also
DLB> suspect that, with two clients and a server, you'd see the same behavior
DLB> -- the "non-input" client will be running at a lower priority, thereby
DLB> achieving a lower frame-rate.

DLB> It also sounds like your server is doing something like:

DLB> loop
DLB> if socket has data then
DLB> read socket
DLB> compute new state
DLB> send reply
DLB> end if
DLB> do nasty computation
DLB> end loop

DLB> This logic will suck up as much CPU time as the OS will give the
DLB> program... While if the client looks like

DLB> loop
DLB> send data to server
DLB> read reply (blocking)
DLB> do nasty computation
DLB> end loop

DLB> then it not only has to compete for CPU time, it does nothing while
DLB> waiting for the server to handle the section inside the IF block.

DLB> But what would happen if you put something like os.sleep(0.025)
DLB> inside the loops? Assuming the loop takes 0.025sec to process, the total
DLB> comes to 0.05 seconds (20fps) AND releases the CPU for the other process
DLB> to compute.

DLB> --
DLB> > ================================================== ============ <
DLB> > wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
DLB> > wu******@dm.net | Bestiaria Support Staff <
DLB> > ================================================== ============ <
DLB> > Home Page: <http://www.dm.net/~wulfraed/> <
DLB> > Overflow Page: <http://wlfraed.home.netcom.com/> <

--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Jul 31 '05 #4

P: n/a
On Sun, 31 Jul 2005 10:31:30 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:
Yes, that's what I have. I was already told I should have 1 server and
2 clients, well I will, but I'd really like to make it work the
master-slave way now.

To answer the rest of your message: the "client" and "server" (C and S
below) are actually equal in my implementation. They both compute
everything. I was told it's not smart to do that, but I can't see why
is it better to have server compute everything: there are only 2
players, and there's quite not much computations, while transferring
current status is much more traffic-consuming than simply transferring
user motions.
I don't know about your game, but the clients should be involved
with the User Interface processing, responding to relatively short
status messages involving those items that can be moved (if you have a
scheme that is doing graphical destruction of the backgrounds too, you
do have more data to transfer).

The server should basically handle the multiple client
connection logic, and determination of interactions between movable
objects -- collision detection, for example (and I don't mean in the
terms of graphics rendering but in terms of object one at current
movement intersecting object two moving at some other vector).
Below I outline what S and C do:

S:
loop
draw screen
accept player1 input from mouse/kbd
send player1 input to C
process player1 input
hang till C sends us player2 input
^^^^^^^^^^^^^^^^^^

Neither should "hang" (block) for the other, since that will
basically turn the system into a turn-based system (and turn-based
systems don't really have "frame-rates").

I'm also NOT a game programmer, so I'm not sure how well most of
them separate screen updates from I/O, but I'd turn the above loop into
something like:
create screen thread
create I/O thread

{screen thread}
loop:
compute/display screen using snapshot of "local status"

{I/O thread}
loop
if keyboard has activity
read data
send data to server
if server has activity
read data
update local status

Note that the keyboard, in this simple example, never affects
the local (client) display -- only the status sent back by the server is
used. Okay, you may need to process things like "quit" locally <G>.

This scheme allows multiple keys/server updates to be captured
without using a blocking operation (the I/O thread should use something
like socket.select() -- but on Windows, that doesn't work for non-socket
I/O streams... might need to create a keyboard thread and a socket
thread, and have both use a "Queue" to transmit to the master I/O
thread). The display update, however long it takes, uses an
instantaneous snapshot of the "local status" (so things don't move while
it computes the frame), but the frame computed will reflect all
key/server activity that occurred.

The server looks like:

loop
if new client connect
add client to list of clients
send client current status
if data from client
update world state (collision detects, damage, etc.)
for c in client list
send current status
if client disconnect
remove client from list
Recall my warning -- I'm not a game programmer; this is just how
/I'd/ consider implementing something like this.
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Jul 31 '05 #5

P: n/a
Again, thank you very much for your help.

DLB> The server should basically handle the multiple client
DLB> connection logic, and determination of interactions between movable
DLB> objects -- collision detection, for example (and I don't mean in the
DLB> terms of graphics rendering but in terms of object one at current
DLB> movement intersecting object two moving at some other vector).

My problem is: there are about 30 movable objects, so transferring
all their coordinates is much more traffic consuming (about 150 bytes
per transfer) rather than sending only user's motions (10 bytes per
transfer). But on the other hand, sending user's motions between two
non-server-neither-clients means that I needed stricted
synchronization, which means the turn-based approach, as you've said.
DLB> I'm also NOT a game programmer, so I'm not sure how well most of
DLB> them separate screen updates from I/O, but I'd turn the above loop into
DLB> something like:
DLB> create screen thread
DLB> create I/O thread

DLB> {screen thread}
DLB> loop:
DLB> compute/display screen using snapshot of "local status"

DLB> {I/O thread}
DLB> loop
DLB> if keyboard has activity
DLB> read data
DLB> send data to server
DLB> if server has activity
DLB> read data
DLB> update local status

DLB> Note that the keyboard, in this simple example, never affects
DLB> the local (client) display -- only the status sent back by the server is
DLB> used. Okay, you may need to process things like "quit" locally <G>.

Well, this look really elegant, but will need me some time to rewrite
my networking that way. Thank's a lot, I'll let you know when it
works.

[..snip..]

]DLB> The server looks like:

DLB> loop
DLB> if new client connect
DLB> add client to list of clients
DLB> send client current status
DLB> if data from client
DLB> update world state (collision detects, damage, etc.)
DLB> for c in client list
DLB> send current status
DLB> if client disconnect
DLB> remove client from list

consider this part:
DLB> if data from client
DLB> update world state (collision detects, damage, etc.)
DLB> for c in client list
DLB> send current status
the problem is - I should do this not "if data from client", but every
50 milliseconds or so, because objects are still moving when not
affected by users. To give you a better idea of what my game is:

Each player controls a snake, which is 2 to 12 balls connected to each
other with ropes; by mouse motions you move the snake's head, and the
rest of the body moves adhering normal physics. The objective/gameplay
is unimportant here, but if you're curios - all the balls of your
snake are bullets, and right-clicking releases current tail. So, you
have to spin around, and release the tail in appropriate moment so it
reaches your opponent, causing as much damage as much impulse it had.
There are health-pots and other stuff on game field of course.

So, you see - server will have to send current status as much time per
second, as much fps I want, and that's quite a lot of data.

I'd also like to mention (if I haven't already) that I have a 33.6
modem, while the friend I'm testing with has a 2 Mbit dedicated line,
if this is the right term.
I also was advised (by Peter Hansen) to try using Twisted, Pyro os
something like that. I've looked at Pyro, and tried using it, without
a lot of success compared to what I have now. I'm starting a new topic
here, describing my experiment.
DLB> Recall my warning -- I'm not a game programmer; this is just how
DLB> /I'd/ consider implementing something like this.
You're being very helpful anyway :)
DLB> --
DLB> > ================================================== ============ <
DLB> > wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
DLB> > wu******@dm.net | Bestiaria Support Staff <
DLB> > ================================================== ============ <
DLB> > Home Page: <http://www.dm.net/~wulfraed/> <
DLB> > Overflow Page: <http://wlfraed.home.netcom.com/> <

--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Aug 1 '05 #6

P: n/a
On Mon, 1 Aug 2005 18:07:59 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:

My problem is: there are about 30 movable objects, so transferring
all their coordinates is much more traffic consuming (about 150 bytes
See below...
consider this part:
DLB> if data from client
DLB> update world state (collision detects, damage, etc.)
DLB> for c in client list
DLB> send current status
the problem is - I should do this not "if data from client", but every
50 milliseconds or so, because objects are still moving when not
affected by users. To give you a better idea of what my game is:
That, unfortunately, gets back to the problem with select() on
Windows -- though still work here as the "data from client" is presumed
to be via socket... The select() call takes a timeout, so you could do
motion updates if needed...
Each player controls a snake, which is 2 to 12 balls connected to each
other with ropes; by mouse motions you move the snake's head, and the
rest of the body moves adhering normal physics. The objective/gameplay
For purposes of the motion this snake -- the game rendering side
(the client) probably should handle the physics. The only part being
actively controlled is the head, and only the head movement needs to be
sent -- the clients respond to head movement and compute the effect on
the rest of the body. IOW, the head and /attached/ balls are ONE object
for purposes of server I/O, not "2 to 12".
is unimportant here, but if you're curios - all the balls of your
snake are bullets, and right-clicking releases current tail. So, you
have to spin around, and release the tail in appropriate moment so it
At this point, you've added another object to track -- but it
sounds like all you need to send is a vector (start position, direction,
speed). The server, on each "input" can compute -- based on the
situation at that moment -- if an intersect will occur, and when. That
state doesn't change unless on or the other player inputs some new
command (the target player, most likely, trying to avoid impact). Upon
the new input, the server interpolates all moving objects -- that is,
its prior update (time T0) says an intersect will occur at time T0+t,
and the player response came in at t/2 (halfway, for simplicity). The
server would compute positions for tracked objects at (T0+t/2), then
apply the new motion vectors (player changed heading), transmit all this
to all clients, and determine the next intersect time. The server
doesn't have to do anything until either this intersect time or a play
input comes in.
So, you see - server will have to send current status as much time per
second, as much fps I want, and that's quite a lot of data.
No... Frame rate is independent. Each client should perform some
tests to determine what frame rate they can support, and adjust their
internal time-steps to that. The server should probably send a
time-stamp so clients can adjust for running over (might result in small
jerks on slow machines, say). Of course, the server will need to check
its clock speed to determine what size a time step will be (and maybe
send that to clients so clients can compute a clock factor for internal
calculations -- especially if the server is using a "simulation clock"
for speed rather than wall clock time)

Say the "snake" is moving left to right at 100 pixels (or some
game internal unit) per second, and client one can only run 5FPS; that
means each rendering pass uses the head position as:
P(f) = P(T0) + (100/5)*f.
{P(f) is Position(frame); P(T0) is the position at the start, the last
status received from the server; 100/5 is the speed divided by the frame
rate = speed per frame}

The other client may be running 50FPS... For that client, the
same status turns into:
P(f) = P(T0) + (100/50)*f

The first player sees the snake move 20 pixels per frame. The
second player will see it move 2 pixels per frame, but will see 10
frames in the time the first player sees one.

In any event, the server is not continuously sending data. It
only sends when it receives a client movement (which changes the state
of the "world") or when a computed event has happened (a "bullet" has
hit a target). "Bullets" are predictable; with no changes in from
clients, the server can compute when the "bullet" will hit, and set up a
timer for that event (canceling the time if a client moves).

So, assuming something like select(in, out, sleep) [I may have
in/out reversed]...

loop
if select(clients_in, None, time_to_next_event)
if time_out
compute damage
if clients_data
compute changes in state
send updated states
computer time_to_next_event
Ah well, I'm late for work... need to run....

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 1 '05 #7

P: n/a
sorry for emailing privately, pressed the wrong "reply" button
Each player controls a snake, which is 2 to 12 balls connected to each
other with ropes; by mouse motions you move the snake's head, and the
rest of the body moves adhering normal physics. The objective/gameplay
DLB> For purposes of the motion this snake -- the game rendering side
DLB> (the client) probably should handle the physics. The only part being
DLB> actively controlled is the head, and only the head movement needs to be
DLB> sent -- the clients respond to head movement and compute the effect on
DLB> the rest of the body. IOW, the head and /attached/ balls are ONE object
DLB> for purposes of server I/O, not "2 to 12".
Well, that's exactly how I think of it.
is unimportant here, but if you're curios - all the balls of your
snake are bullets, and right-clicking releases current tail. So, you
have to spin around, and release the tail in appropriate moment so it
DLB> At this point, you've added another object to track -- but it
DLB> sounds like all you need to send is a vector (start position, direction,
DLB> speed). The server, on each "input" can compute -- based on the
DLB> situation at that moment -- if an intersect will occur, and when. That
DLB> state doesn't change unless on or the other player inputs some new
DLB> command (the target player, most likely, trying to avoid impact).
But that happens all the time, and lots of times per second! If you
played Quake, CS or even UT :), you know that you hold your "forward"
key pressed all the time, and you also move your mouse aiming on
target almost all the time. And when I play Quake, I *see* how my
opponent's model aims at me, I mean, his mouse motions are transferred
to me.
Well, I suppose that Quake doesn't send mouse motion, clients
probably retrieve the resulting aiming direction from server, but in
my case, as you said yourself, client side should do physics'
computations.

DLB> Upon the new input, the server interpolates all moving objects -- that is,
DLB> its prior update (time T0) says an intersect will occur at time T0+t,
DLB> and the player response came in at t/2 (halfway, for simplicity). The
DLB> server would compute positions for tracked objects at (T0+t/2), then
DLB> apply the new motion vectors (player changed heading), transmit all this
DLB> to all clients, and determine the next intersect time. The server
DLB> doesn't have to do anything until either this intersect time or a play
DLB> input comes in.
That's the problem - "or a player input comes in". As I've explained,
this happens a dozen of times per second :(. I've even tried not
checking for player's input after every frame, but do it 3 times more
rare (if framecount % 3 == 0 : process_players_input()). Well, I've
already got it that I shouldn't tie this around framerate, but
nevertheless...
So, you see - server will have to send current status as much time per
second, as much fps I want, and that's quite a lot of data.

DLB> No... Frame rate is independent. Each client should perform some
DLB> tests to determine what frame rate they can support, and adjust their
DLB> internal time-steps to that. The server should probably send a
DLB> time-stamp so clients can adjust for running over (might result in small
DLB> jerks on slow machines, say). Of course, the server will need to check
DLB> its clock speed to determine what size a time step will be (and maybe
DLB> send that to clients so clients can compute a clock factor for internal
DLB> calculations -- especially if the server is using a "simulation clock"
DLB> for speed rather than wall clock time)
I'm afraid I'm loosing it. Let's consider your example:

DLB> Say the "snake" is moving left to right at 100 pixels (or some
DLB> game internal unit) per second, and client one can only run 5FPS; that
DLB> means each rendering pass uses the head position as:
DLB> P(f) = P(T0) + (100/5)*f.
DLB> {P(f) is Position(frame); P(T0) is the position at the start, the last
DLB> status received from the server; 100/5 is the speed divided by the frame
DLB> rate = speed per frame}

DLB> The other client may be running 50FPS... For that client, the
DLB> same status turns into:
DLB> P(f) = P(T0) + (100/50)*f

DLB> The first player sees the snake move 20 pixels per frame. The
DLB> second player will see it move 2 pixels per frame, but will see 10
DLB> frames in the time the first player sees one.

This sounds transparent, but my slow client isn't able to process
networking fast enough, so even if it's able to work at 30 fps, it
can't draw those 30 frames, because input from other player comes
instantly, about 10 times per second, and server tries sending this to
all clients. So my slow client simply can't know current true status,
thus has nothing to draw, because it can't handle 10 transfers per
second. And if server doesn't send user motions equal number of times
to all clients, while they compute the world's status, they will
happen to have different pictures :(

--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Aug 2 '05 #8

P: n/a
Michael Rybak wrote:
That's the problem - "or a player input comes in". As I've explained,
this happens a dozen of times per second :(. I've even tried not
checking for player's input after every frame, but do it 3 times more
rare (if framecount % 3 == 0 : process_players_input()). Well, I've
already got it that I shouldn't tie this around framerate, but
nevertheless...


There's the key. How are you processing network input, specifically
retrieving it from the socket?
Aug 2 '05 #9

P: n/a
CS> Michael Rybak wrote:
That's the problem - "or a player input comes in". As I've explained,
this happens a dozen of times per second :(. I've even tried not
checking for player's input after every frame, but do it 3 times more
rare (if framecount % 3 == 0 : process_players_input()). Well, I've
already got it that I shouldn't tie this around framerate, but
nevertheless...


CS> There's the key. How are you processing network input, specifically
CS> retrieving it from the socket?

A "sock" class has a socket with 0.00001 timeout, and every time I
want anything, I call it's read_command() method until it returns
anything. read_command() and send_command() transfer user's actions in
special format so that it takes 10 bytes per transfer.
I believe this should be rewritten to be done in a separate thread, and
that *current* user input should be processed as *next* one:
while 1:
render()
inp = get_player_input()
thread.start_new(send_inp, (inp,))
thread.start_new(accept_opponents_inp, ())
while still_no_opponents_input_from_previous_iteration()
time.sleep(0.05)
process_previous_player_input()
physics.make_step

I will try writing it that way, but I doubt it shall make things much
better... You see, I've tried the normal 1-server-2-clients approach
with Pyro (and today with simulating RMI proxy via UDP), and resulted
with nothing comforting. Please read the "using Pyro for network
games" topic here for details.

--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Antivirus alert: file .signature infected by signature virus.
Hi! I'm a signature virus! Copy me into your signature file to help me spread!


P.S. here's the sock class. My server_sock and client_sock are derived
from it, with additional accept_connection and establish_connection
methods respectively.

#sock.py
import socket
import com_network
import constants as c_
class sock:
def __init__(self, host):
self.host = host
self.port = c_._PORT

self.sockobj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sockobj.settimeout(0.00001)

self.curcon = None #connection will be created and saved here
self.connected = False

def read_command(self):
"""format:
command_id - 1 byte
command_size - CMD_LEN_BIT_SIZE bytes
command_text - command_size bytes

returns a triple (int id, int size, str text)"""

if not self.connected:
return (None, None)
cmd = com_network.read_fixed(self.curcon, 1)
if len(cmd) < 1: #no cmd
return (None, None)
sz = com_network.read_fixed(self.curcon, CMD_LEN_BIT_SIZE)
cmd, sz = str_to_cmd(cmd + sz)
text = com_network.read_fixed(self.curcon, sz)
return (cmd, text)

def send_command(self, cmd, obj):
send_text(self.curcon, com_network.cmd_to_str(cmd, str(obj)))
def close(self):
if self.connected:
self.connected = False
self.curcon.close
self.curcon = None
self.sockobj.close()

Aug 2 '05 #10

P: n/a
On Tue, 2 Aug 2005 10:16:13 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:

But that happens all the time, and lots of times per second! If you
played Quake, CS or even UT :), you know that you hold your "forward"
key pressed all the time, and you also move your mouse aiming on
Are you sure the server or client isn't smoothing things out...
For example, holding down your "forward" button may just mean the client
sent ONE "forward ON" at the start, and doesn't send anything more until
you release the key (when it sends a "forward OFF"). Could also smooth
mouse movements, only sending them when they jitter far enough from some
point.
Well, I suppose that Quake doesn't send mouse motion, clients
probably retrieve the resulting aiming direction from server, but in
my case, as you said yourself, client side should do physics'
computations.
The server most likely is transmitting just the position and
facing (direction) information -- 6 numeric values (XYZ position, XYZ
direction/speed vector). If the game is really starved for time, they
could be mapping directions to bytes -- 0..360degrees mapped to 0..255,
meaning the smallest direction change handled is 360/255 => ~1.4deg.
That means the direction vector is only 3 bytes long. Position is
probably 16-bit each, unsigned, allowing 0..65536 discrete positions in
each direction. Things like controlling arms & legs could be solely
client side -- if the "body" center standing up is +4 units (assume a
unit is "foot"), then a body center that is only 2 units above the
"floor" must be crouching. Walking too -- the client "knows" the
position has changed by x-units in some direction; the client animates
leg movement "knowing" that the legs must be on the "floor" and below
the body by some margin (say +/- 2 units for a four foot stride).

That's the problem - "or a player input comes in". As I've explained,
this happens a dozen of times per second :(. I've even tried not
checking for player's input after every frame, but do it 3 times more
rare (if framecount % 3 == 0 : process_players_input()). Well, I've
already got it that I shouldn't tie this around framerate, but
nevertheless...
The input data should be processed without being tied to frame
rate... The frame update should only use the /most recent/ data...
Essentially, you throw out anything that you couldn't process in time --
which means the slowest client /will/ look jerky.

Even for your simple 2-D snakes, two snakes and say four "shots"
is six objects. Six objects of: (ID, Type, (px, py, pz), (vx, vy, vz))
and using 16-bit ints results in 16 bytes per object, 96 bytes to update
the "world"... Add some packet overhead and call it 128 bytes. On a
28.8Kbps modem (with no compression, 10bits per byte), you should get
2880 bytes/second, or 22 "world updates" per second. And those should
take very little CPU time to just parse and update the object states
{pseudocode}
object(ID).update(position, velocity)

The start of the frame update would make snapshot (deepcopy) of
all objects so they don't change during the frame computation. Even
while the frame computation is taking place, you should be accepting
updates from the server -- they just don't have any effect: if you are
getting five frames/second for display, and server updates at 22/second
(call it 20) then you will have four
object(ID).update(position, velocity)
passes per frame -- only the last one will be around when the next frame
begins.

Your clients may need to know what comm-rate they have, and
inform the server not to send data faster than can be streamed. There's
no sense having a server sending DSL rate (over 220 updates/second, say,
if it will take 10 seconds for your end to read them).
This sounds transparent, but my slow client isn't able to process
networking fast enough, so even if it's able to work at 30 fps, it
can't draw those 30 frames, because input from other player comes
instantly, about 10 times per second, and server tries sending this to
DisplayThread I/OThread
T0 frame -
T0+1 frame -
T0+2 frame update
T0+3 frame-using-new -
T0+4 frame -
T0+5 frame update
T0+6 frame-using-new
etc

There shouldn't be that much data in an update... Even on a slow
dialup client it could receive some 20 world updates per second (+ or -
depending on how many actual "shots" are in motion). These updates
should only be data copies into the "world object" map... The only real
computations are in the frame display. The frame display has to be
extrapolating in between updates anyways.
all clients. So my slow client simply can't know current true status,
thus has nothing to draw, because it can't handle 10 transfers per
second. And if server doesn't send user motions equal number of times
to all clients, while they compute the world's status, they will
happen to have different pictures :(
That's likely what happens in the other games too -- but the
differences are close enough not to be apparent. The primary factor is
that the client has to be synchronized to the same simulation /time/.
Everything else in extrapolated from position/velocity (velocity
includes direction) at time T0 to the frame time T0+t

The only real case where one can not extrapolate over a time
span is when the server (which should be the fastest machine in the
system) has determined an intersection has occurred. If the server says
a "bullet" has hit a "target", it should identify both the bullet and
target and the client must respond appropriately with a "hit" reaction.
The client can't just go from "bullet" in front of "target" to "bullet"
behind "target" just because that is where the frame update says it now
is.
If your slower client is being swamped by world updates, then
you likely must implement a throttle in the server logic. Each client
reports the rate at which they can receive updates, and the server only
sends updates to that client at that rate. Again, this may mean for
highly mismatched clients, that the slow client may only get one update
for every 10 that the fast client gets.

Something rudimentary like having the server send 10 seconds
worth of "typical" world updates with time stamps... So server data for
first and last packets should be

T0, T0+10sec

and maybe that was 100 world updates (10/sec)

Slow client receives the first at T0, but the last (packet 100) comes in
at T0+60. Fast client receives all packets in T0+10...

It took 60 seconds to receive 10 seconds of data. Client sends
back to server a rate of 6. Other client sends back rate of 1.

Server now uses a modulo function on packet sends...

for c in client
if t mod c.rate = 0
send current world packet to client
You may want to throttle the server anyways -- say only send an
update every 0.1 second
(time to go to work -- and I still haven't showered!)
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 2 '05 #11

P: n/a
Michael Rybak wrote:
CS> There's the key. How are you processing network input, specifically
CS> retrieving it from the socket?

A "sock" class has a socket with 0.00001 timeout, and every time I
want anything, I call it's read_command() method until it returns
anything. read_command() and send_command() transfer user's actions in
special format so that it takes 10 bytes per transfer.


So when you want player input, you explicitly halt the program until you
receive it, inside a while loop? No wonder your programs aren't
behaving well, then.

Network processing Is Not Slow. Unless you're sending near the maximum
capacity of your line, which you're obviously not[1], the slowness is
architectural.

[1] - The TCP packet contains at most 28 bytes of overhead, so combine
that with 10 bytes of data and you're looking at 38 bytes/packet. A
33.6 modem can handle 4.2kB/sec, cut that in half for a safety margin
for 2.1kB/sec. That will handle about 55 updates/second, which you
shouldn't be reaching if you're "just sending updates when a player does
something."

Why are you messing with sockets directly, to begin with? It looks like
you want an asynchronous socket interface, so that you don't explicitly
loop and wait for data from the nyetwork for updates.

In addition to making Julienne fries, Twisted is an excellent framework
for asynchronous network IO. For a naive, non-threaded implementation,
you'd schedule your update code as a timed event, and you'd define a
Protocol for handling your network stuff. When you receive data, the
protocl would update your application's state, and that would be picked
up automagically the next time your update event ran.

In a threaded implementation, you'd run your update code to a thread
(DeferToThread), and your network code would post updates to a
synchronous queue, read by your update code.
Aug 2 '05 #12

P: n/a
On Tue, 2 Aug 2005 19:31:55 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:
while 1:
render() inp = get_player_input()
thread.start_new(send_inp, (inp,))
thread.start_new(accept_opponents_inp, ())
You don't understand threading either, it appears. Here you are
starting a new thread for each input you want... There should just be AN
input thread, started at the very beginning, and it should just wait for
input, then update the global state so the "update step" can do
whatever.

Also, recommend you use threading, not thread as the module.

SERVER
An input thread would look something like:

while True:
data = socket.read() #assumes both clients write to same socket
#otherwise use a select(client_socket_list)
#followed by socket.read for the flagged socket(s)
parse data
lock global
save in global state variables
unlock global

That is all

Update thread
while True:
lock global
copy state variables to local
unlock global
compute new world state (check for collisions -- "bullet" hits)
for c in client_list
send world state to c

CLIENT
User-input thread
while True:
ch = keyboard
compute effect of ch
send controlled object(s) state to server

server-input thread
while True:
world_state = socket.read
lock global
update global with world_state
unlock global

rendering thread
while True:
lock global
copy global world_state to local
unlock global
render graphics based on local world_state

main "thread"

connect to server
get initial world state -- may include static stuff (background map)
start rendering thread
start server-input thread
start user-input thread
wait(until dead)
The client rendering thread (and server update thread) only see
the most recent state of data at the top of the loop.
while still_no_opponents_input_from_previous_iteration()
time.sleep(0.05) You're still focused on a turn based system, it looks like... process_previous_player_input()
physics.make_step

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 3 '05 #13

P: n/a
I was a bit unhappy to read this, because what you describe here is
just what I've tried yesterday in my test-game with 2 balls, so if
I've pointed that out, you wouldn't have to say I
DLB> don't understand threading either, it appears.
:'(

Thank you very much for putting so much effort in making things clear
to me, *this* email of your made everything clear as never. Still I
have problems, and hope you still don't mind me asking.

Some comments:
while 1:
render() inp = get_player_input()
thread.start_new(send_inp, (inp,))
thread.start_new(accept_opponents_inp, ())
DLB> You don't understand threading either, it appears. Here you are
DLB> starting a new thread for each input you want...
and
while still_no_opponents_input_from_previous_iteration()
time.sleep(0.05)

DLB> You're still focused on a turn based system, it looks like...

Now, that's *not* how I'm tending to do it; that's what I was thinking
of while trying the turn-based approach, and describing here;
Christopher Subich asked how it was done initially, so I brought my
hanging system out of shame again, and added something I was thinking
about to improve it, while I already realize that's not the way to go
- from your previous comprehensive posts.
DLB> There should just be AN input thread, started at the very beginning,
DLB> and it should just wait for input, then update the global state so
DLB> the "update step" can do whatever.

As stated above, that's how I'm trying it right now. Still, if doing
it turn-base, I would have to create a new thread every time.
I have some other questions though - please see below.

DLB> Also, recommend you use threading, not thread as the module.
Surely will, why?

DLB> SERVER
DLB> An input thread would look something like:

DLB> while True:
DLB> data = socket.read() #assumes both clients write to same socket
DLB> #otherwise use a select(client_socket_list)
DLB> #followed by socket.read for the flagged socket(s)
DLB> parse data
DLB> lock global
DLB> save in global state variables
DLB> unlock global

Now, few questions. Do I need to time.sleep(0.xxx) in any of these
while True: loops, not to overwhelm CPU? I can measure the time at
beginning and end of each iteration to make things happen fixed number
of times per second, but should I? And another: do I get it right that
instead of "lock global" you mean:
while global.locked:
time.sleep(0.001)
lock global
And I also wonder how do I make sure that 2 threads don't pass this
"while" loop simultaneously and both try locking global. There is a
probability, not?

Now, for update thread:

DLB> That is all

DLB> Update thread
DLB> while True:
DLB> lock global
DLB> copy state variables to local
DLB> unlock global
DLB> compute new world state (check for collisions -- "bullet" hits)
DLB> for c in client_list
DLB> send world state to c

In my yesterday experiment, I have a separate thread for each of 2
clients, and what I do there is:

def thr_send_status(player_sock):
while 1:
t, sub_addr = player_sock.recvfrom(128) #player ready to accept
player_sock.sendto(encode_status(g.get_status()), sub_addr)

I'm reading 1 byte from client every time before sending new update to
him. OK, Ok, I know that's not good, ok. Now, I like your idea much
more, where you say we first measure the processing speed of each
client, and send data to every client as often as he can process it:

DLB> Slow client receives the first at T0, but the last (packet 100) comes in
DLB> at T0+60. Fast client receives all packets in T0+10...

DLB> It took 60 seconds to receive 10 seconds of data. Client sends
DLB> back to server a rate of 6. Other client sends back rate of 1.

DLB> Server now uses a modulo function on packet sends...

DLB> for c in client
DLB> if t mod c.rate = 0
DLB> send current world packet to client
Yes, this I great, but what if speed changes? Should I retest this
around every 10 seconds? I mean, server sending too much data to a
client is ok for server, but very bad for a client, since it starts
hanging and loses synchronization, unless I use a timestamp to throw
away late states (I think I need to re-read all your previous posts,
you've explained about synchronizing already).
While thinking about this, I've decided to go the wrong way, and to
wait for confirmation from client before sending next pack.

Still, it shouldn't slow anything a lot, because client does this:

def thr_get_status(self, g, player_sock, player_id):
while 1:
player_sock.sendto("!", addr) #ready
self.local_status = decode_status(player_sock.recvfrom(128)[0])
g.set_status(self.local_status)
So they simply exchange data all the time in separate threads, even
through separate sockets (not to dispatch the confirmations from
different players into corresponding threads via global flags), which
makes the "ready" thing ok from speed point of view, but I prefer
your way, quoted above, so my question is still valid - do I
remeasure speed?

I'm also almost sure it's wrong to have separate sockets and threads
for each player, you say I should select()/dispatch instead, but I'm
afraid of that some *thing* being wrong with select() for Windows.
Somehow, I'm doing a lot of thins the wrong way :(
Before describing another problem I've encountered, I thought I'd
remind you of what my test game is: each player controls it's ball by
moving mouse pointer, towards which his ball starts moving; that's it.

When I first tried this with threads, 1 client ran nearly perfect. But
when running 2 clients via localhost, they eat cpu away, and bad things
happen.

Now, you see, sending user motions to server appears to be faster (or
at least not slower) than getting new status, so, as a result, I have
the following picture: I place my pointer somewhere, and the ball runs
to it, and then runs a bit beyond it, because by the moment server
knows the ball is already at my pointer, client still thinks it's not.

Several seconds later, thins "a bit beyond" becomes "a lot beyond",
and finally both balls run away from game field, being helpless; seems
like I/O thread being much more productive than send_status one?

I thought that the reason is my stupid "ready" check before every
status update, and removed it. As a result, even single client via
local host was very slow, but no artifacts.

This all was when I had *no* time.sleeps in the while 1: loops.
So I added time.sleep(0.005) to server's send_status loop and to
client's send_user_action loop. Things became better, but still balls
are spinning around the mouse pointer instead of running under it.
Every time client tries moving towards the mouse, it's ball is already
at another place at server, and it runs in wrong direction.

Obviously, if I have these problems in such a primitive test at
localhost, I shouldn't even try running it online with the Snakes :(
Thanks again for being this helpful, Dennis, and thank you for your
patience!
--
Best Regards,
Michael Rybak mailto:ac******@ukr.net

Antivirus alert: file .signature infected by signature virus.
Hi! I'm a signature virus! Copy me into your signature file to help me spread!

Aug 3 '05 #14

P: n/a
Michael Rybak wrote:
As stated above, that's how I'm trying it right now. Still, if doing
it turn-base, I would have to create a new thread every time.
I have some other questions though - please see below.
No, you should never need to create a new thread upon receiving input.
What you want is inter-thread communication, a synchronous queue.

A synchronous queue is a thread-safe queue. You'd push event updates to
it from the communication thread, and in the update thread, WHICH IS
ALWAYS RUNNING, you'd check the queue each loop to see if there was
anything new.
Now, few questions. Do I need to time.sleep(0.xxx) in any of these
while True: loops, not to overwhelm CPU? I can measure the time at
beginning and end of each iteration to make things happen fixed number
of times per second, but should I? And another: do I get it right that
instead of "lock global" you mean:
while global.locked:
time.sleep(0.001)
lock global
And I also wonder how do I make sure that 2 threads don't pass this
"while" loop simultaneously and both try locking global. There is a
probability, not?
You have the right idea, that locking's important, but when the
grandparent poster said "lock global," he meant "lock global." Locks
are low-level primitives in any threading system, they can also be
called mutexes.

Attempting to acquire a lock returns immediate if the lock can be
acquired; if it can't (and it's set to block, which is the default) the
thread will wait until it -can- acquire the lock -- the entire thrust of
your 'time.sleep' loop, only good.

See thread.acquire and threading.Lock for python built-in locks.
In my yesterday experiment, I have a separate thread for each of 2
clients, and what I do there is:

def thr_send_status(player_sock):
while 1:
t, sub_addr = player_sock.recvfrom(128) #player ready to accept
player_sock.sendto(encode_status(g.get_status()), sub_addr)

I'm reading 1 byte from client every time before sending new update to
him. OK, Ok, I know that's not good, ok. Now, I like your idea much
more, where you say we first measure the processing speed of each
client, and send data to every client as often as he can process it:
Just how much data are you sending in each second? Testing client speed
and managing updates that way is relatively advanced, and I'd argue that
it's only necessary when your data has the potential to swamp a network
connection.
While thinking about this, I've decided to go the wrong way, and to
wait for confirmation from client before sending next pack.
No, you definitely don't need to do this. TCP is a reliable protocol,
and so long as the connection stays up your client will receive data
in-order with guaranteed arrival.

If you were using UDP, then yes you'd need (possibly) to send
confirmation, but you'd probably need a more advanced version to handle
missing / out-of-order packets.
I'm also almost sure it's wrong to have separate sockets and threads
for each player, you say I should select()/dispatch instead, but I'm
afraid of that some *thing* being wrong with select() for Windows.
Somehow, I'm doing a lot of thins the wrong way :(
Just use the Twisted library. It abstracts that away, and not touching
sockets is really much nicer.
Before describing another problem I've encountered, I thought I'd
remind you of what my test game is: each player controls it's ball by
moving mouse pointer, towards which his ball starts moving; that's it.


What's the nature of your evend update? Do you say "mouse moved N" or
"mouse moved to (123,456)?" If it's the latter, then without motion
prediction there's no way that either simulation should have the ball
overshoot the mouse. Synchronization, however, will still be an issue.
Aug 3 '05 #15

P: n/a
On Wed, 3 Aug 2005 12:24:58 +0300, Michael Rybak <ac******@ukr.net>
declaimed the following in comp.lang.python:
I was a bit unhappy to read this, because what you describe here is
just what I've tried yesterday in my test-game with 2 balls, so if
I've pointed that out, you wouldn't have to say I
I'll confess that I may have missed some intervening comments.
(Hmmm, I see you've dropped the snakes -- I must have missed that; most
of the following is still snake oriented)

Also, please take into account that my code samples are
pseudo-code, not real Python.
Now, that's *not* how I'm tending to do it; that's what I was thinking
of while trying the turn-based approach, and describing here;
Christopher Subich asked how it was done initially, so I brought my
hanging system out of shame again, and added something I was thinking
about to improve it, while I already realize that's not the way to go
- from your previous comprehensive posts.
I think (today at least, ask me tomorrow and the answer might
change -- after all, my missive yesterday morning ran so long I was late
getting to work! That doesn't improve one's mood <G>).... Uh... I think
your initial effort probably should be just to get the separation of
functionality working regardless of speed.

On that thought, I have a few non-essential musings: Is your
"world" open or bounded (ie, can you go off one side and come in from
the opposite, or do you bounce); Do your "shots" have a lifetime or
(related to bounded) end on impact with anything. And for initial
simplification, I'd consider a "hit" to be a shot intersecting only the
"head" -- let shots and bodies cross each other (this lets the server
only worry about head position/vector and shot position/vector -- no
overhead for tracking all tail segments for impact).

As stated above, that's how I'm trying it right now. Still, if doing
it turn-base, I would have to create a new thread every time.
If doing turn-based, you don't use threads -- nothing happens
/until/ an input is received.
I have some other questions though - please see below.

DLB> Also, recommend you use threading, not thread as the module.
Surely will, why?
It's a higher level interface, with fancier support. "thread"
just has the start operation, and a single type of lock. "threading" has
the ability to set a thread to daemon status (it goes away when all
non-daemon threads end, no need to explicitly tell it to stop), "join"
(wait for thread to finish), basic lock, reentrant lock, condition
variables, semaphores, and events.
DLB> SERVER
DLB> An input thread would look something like:

DLB> while True:
DLB> data = socket.read() #assumes both clients write to same socket
DLB> #otherwise use a select(client_socket_list)
DLB> #followed by socket.read for the flagged socket(s)
DLB> parse data
DLB> lock global
DLB> save in global state variables
DLB> unlock global

Now, few questions. Do I need to time.sleep(0.xxx) in any of these
while True: loops, not to overwhelm CPU? I can measure the time at
The input thread, if used (since I can visualize variations of
the server logic that don't need threads) should be blocking on the
socket read. If anything, it is the /clients/ that should have sleeps()
to avoid overloading the server.

But (I did warn you my views can change from day to day) if the
server does not have to perform periodic computations: ie, it computes
effects based on the last received input, and sends those results to the
clients, it can then wait until a client reacts to those results. In
/this/ case, the entire server is just

while True:
data = socket.read()
compute new world state (include time of next "impact")
for c in client_list:
send world state to c, including "now" and "impact" time
#if a client hasn't responded by "impact" time
#the impact takes place and the client(s) should reflect
#the damage

The periodic computation mode gets closer to a true simulation
engine. The server will need the two threads. An input thread which
blocks until it gets asynchronous client data, and a computation thread
synchronized to the simulation clock (say 4 updates per second)
beginning and end of each iteration to make things happen fixed number
of times per second, but should I? And another: do I get it right that
instead of "lock global" you mean:
while global.locked:
"lock global" means acquiring some predefined lock object that
is used to prevent overlapping access to the global data. time.sleep(0.001)
NO!, the lock itself does the blocking -- you don't poll.

Still using pseudo-code, and assuming a single socket is used by
all clients (otherwise you need a select and indexed read into the
correct socket).

#####

World_Lock = threading.Lock()
..... #initialize world state

def inputThread():
while True:
data = socket.read()
#assumes data identifies the action type,
#the client, and the object ID
World_Lock.acquire() #block if needed
#update world state with data
World_Lock.release()

def updateThread():
Tnext = time.time() #or some low-level time value
# maybe time.clock()
while True:
Tnext = Tnext + 0.25 #sec -- four updates/second
World_Lock.acquire() #block if input is in action
#compute state for this time increment
# note: this time I'm doing everything inside
# the lock!
for c in client_list:
send world state to client "c"
# alternate is to do a deep copy inside the lock
# and then compute/send the update outside
# the lock (lets input run more often)
World_Lock.release()
time.sleep(Tnext - time.time())
# this adjusts for the processing time inside lock

UT : threading.Thread(updateThread)
IT : threading.Thread(inputThread)

# wait for game end? Do not use a polling loop!
And I also wonder how do I make sure that 2 threads don't pass this
"while" loop simultaneously and both try locking global. There is a
probability, not?
Read the manual for the threading module and the various locks,
events, etc.
In my yesterday experiment, I have a separate thread for each of 2
clients, and what I do there is:

def thr_send_status(player_sock):
while 1:
t, sub_addr = player_sock.recvfrom(128) #player ready to accept
player_sock.sendto(encode_status(g.get_status()), sub_addr)
Problem here is that you've again tied things together -- you
are only sending an update to a client when you receive data from the
same client... If a player walks away from the keyboard, he'll never
update.

Computing the world update AND SENDING it to ALL clients has to
be separate from receiving input from ANY client.
I'm reading 1 byte from client every time before sending new update to
him. OK, Ok, I know that's not good, ok. Now, I like your idea much
Too much overhead... You should be receiving packets that say
something like "client 2 object 1 is at (x, y) moving (dx, dy)" (pack
that as some string of bytes, not this long text description: (2, 1, x,
y, dx, dy); "client 2 object 2 (a tail "bullet") created at (x, y)
moving (dx, dy)"

Assuming dx, dy are, say, pixels/second, and the server is
throttled to 4 updates/second, each update will compute positions as
x, y = x + dx/4, y + dy/4

See if any objects intersect (assuming a circular "object")
if sqrt((x1-x2)^2 + (y1-y2)^2) < radius:
set world state to indicate a collision of objects
(on next update, remove flagged objects?)
more, where you say we first measure the processing speed of each
client, and send data to every client as often as he can process it:

To simplify, you'll notice that "today's" installment has the
server throttled to just four updates/second... Even a WfW3.11 on a
40MHz i386 should handle that <G> Par of my idea of simplifying to get
the logic correct, then add speed ups.

Yes, this I great, but what if speed changes? Should I retest this
around every 10 seconds? I mean, server sending too much data to a
client is ok for server, but very bad for a client, since it starts
hanging and loses synchronization, unless I use a timestamp to throw
Time stamping all transmissions is probably going to be needed
too -- it would let you detect lag -- when the client notices the
received packets are (client_time - packet_time > allowable_lag) -- and
send a special packet to the server to throttle down lower... But I
don't have any easy way to throttle back up if the situation improves
(actually, the server could also check incoming packets for lag and
automatically apply the throttle to that client)

So they simply exchange data all the time in separate threads, even
through separate sockets (not to dispatch the confirmations from
You're adding your packet confirmations on top of the TCP
overhead (TCP doesn't consider a packet to have been received until the
low-level protocol has acknowledged it). That may be why you received
one suggestion to use UDP sockets -- UDP is a "send and forget". The
send just sends and never expects a response -- next update interval,
send a new packet. The assumption is that it is not critical if a packet
is lost in transit as the next packet should carry all the data anyways.
different players into corresponding threads via global flags), which
makes the "ready" thing ok from speed point of view, but I prefer
your way, quoted above, so my question is still valid - do I
remeasure speed?

I'm also almost sure it's wrong to have separate sockets and threads
for each player, you say I should select()/dispatch instead, but I'm
afraid of that some *thing* being wrong with select() for Windows.
The Windows problem with select is that it ONLY works for
sockets. UNIX/Linux select treats sockets and file I/O identically, so
you can use ONE thread to select on both the inbound socket AND the
keyboard. Windows needs a separate thread to handle the keyboard input.

Now, you see, sending user motions to server appears to be faster (or
at least not slower) than getting new status, so, as a result, I have
the following picture: I place my pointer somewhere, and the ball runs
to it, and then runs a bit beyond it, because by the moment server
knows the ball is already at my pointer, client still thinks it's not.
You have two programs both trying to compute the updates, I
suspect. If you notice, in all my examples, client "input" goes directly
to the server. The client only renders the screen based on what the
server sends back. That way, both clients will be rendering based upon
identical information (especially with the above 4 update/second sample)
Several seconds later, thins "a bit beyond" becomes "a lot beyond",
and finally both balls run away from game field, being helpless; seems
like I/O thread being much more productive than send_status one?
No idea about the "run away" -- what I'd have expected is
"nervousness" -- the ball jittering around a non-moving mouse pointer
(whoops, I went past, need to back up... whoops too much, go the other
way).
This all was when I had *no* time.sleeps in the while 1: loops.
So I added time.sleep(0.005) to server's send_status loop and to
client's send_user_action loop. Things became better, but still balls
Well, if there are no blocking I/O calls anywhere, a thread will
suck up all the CPU the OS will give it, then move to another thread.
(Or, in Python, something like 100 byte-codes, I think).
are spinning around the mouse pointer instead of running under it.
Every time client tries moving towards the mouse, it's ball is already
at another place at server, and it runs in wrong direction.
As I said above, it sounds like you have multiple programs EACH
computing the position of the ball. My rough scheme puts all knowledge
of object position and motion in one program (the server), and the
clients only render the display based on what comes from the server.

The client only sends /changes in motion/ (or, for this apparent
magnetic mouse pointer, the mouse position) to the server. The server
computes, from the previous object position and motion, where the object
is at the new quantum (time step), and tells the clients that this is
where to draw the object.

I need to get to work, running late again...

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 3 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.