2-player game, client and server at localhost

Christopher Subich spam.csubich+block at block.subich.spam.com
Wed Aug 3 17:25:45 CEST 2005


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.



More information about the Python-list mailing list