Discussion:
socket.rcv timeout while-loop
Dwayne Blind
2011-02-03 17:56:21 UTC
Permalink
Hi everybody,

I am using Python 3.0.

I have such a code :
b=time.clock()
while time.clock()-b<3 :
data=s.recv(1024)

However I would like to set timeout on the socket rcv method, so that the
while loop stops exactly after 3 seconds. Is this possible ?

Thanks a lot,
Dwayne
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110203/375b5cdb/attachment.html>
Stephen Hansen
2011-02-03 18:04:08 UTC
Permalink
Post by Dwayne Blind
However I would like to set timeout on the socket rcv method, so that
the while loop stops exactly after 3 seconds. Is this possible ?
I rarely do low-level socket stuff -- but I think s.settimeout() is what
you're looking for. It applies to the whole socket, and not just one
method -- so you may want to reset it after you're done recv'n.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20110203/bc6f0566/attachment.pgp>
Dwayne Blind
2011-02-03 18:13:37 UTC
Permalink
Thanks for your answer. I don't want to reset my socket. I want to apply the
timeout to the rcv method only.

What about select ?

http://docs.python.org/library/select.html#select.select

How to implement it ?

Thanks a lot,
Dwayne

2011/2/3 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
However I would like to set timeout on the socket rcv method, so that
the while loop stops exactly after 3 seconds. Is this possible ?
I rarely do low-level socket stuff -- but I think s.settimeout() is what
you're looking for. It applies to the whole socket, and not just one
method -- so you may want to reset it after you're done recv'n.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
--
http://mail.python.org/mailman/listinfo/python-list
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110203/259c726e/attachment.html>
Stephen Hansen
2011-02-03 18:53:01 UTC
Permalink
Post by Dwayne Blind
Thanks for your answer. I don't want to reset my socket. I want to apply
the timeout to the rcv method only.
Setting the timeout does not "reset [your] socket", I don't think. And I
get that you want to only timeout recv... that's why I pointed out its a
socket method, not an argument to recv. If you don't want it to apply to
everything else, you just have to be sure to change it back after recv.

Just:
timeout = s.gettimeout()
s.settimeout(3)
s.recv(1024)
s.settimeout(timeout)

Personally, I'd prefer to do:

with timeout(s, 3):
s.recv(1024)

That's a lot more clear, and I'd roll this context manager to accomplish it:

--- start

from contextlib import contextmanager

@contextmanager
def timeout(sock, timeout):
old_timeout = sock.gettimeout()
sock.settimeout(timeout)
try:
yield sock
finally:
sock.settimeout(old_timeout)

--- end

The contextmanager decorator is an easy/quick way of making a context
manager. Everything up until the yield is executed before the 'with'
block is run, and everything after the yield is executed after the
'with' block concludes.

If the with block throws an exception, it'll be catchable at the yield
point.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20110203/80029777/attachment.pgp>
Dwayne Blind
2011-02-03 23:02:26 UTC
Permalink
Thanks Stephen. It's really nice of you.

I have not understood everything though. (I have never used a context
manager before.)

Here are some comments :

timeout = s.gettimeout() # Is that the default timeout ?
s.settimeout(3) # I guess this is a 3 second timeout
s.recv(1024)
s.settimeout(timeout) # You change it back ?

So with a while loop, it should be :

timeout = s.gettimeout()
s.settimeout(3)
b=time.clock()
while time.clock()-b<3 :
data=s.recv(1024)
s.settimeout(timeout)

Am I right ?

Thanks again,
Dwayne


2011/2/3 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
Thanks for your answer. I don't want to reset my socket. I want to apply
the timeout to the rcv method only.
Setting the timeout does not "reset [your] socket", I don't think. And I
get that you want to only timeout recv... that's why I pointed out its a
socket method, not an argument to recv. If you don't want it to apply to
everything else, you just have to be sure to change it back after recv.
timeout = s.gettimeout()
s.settimeout(3)
s.recv(1024)
s.settimeout(timeout)
s.recv(1024)
--- start
from contextlib import contextmanager
@contextmanager
old_timeout = sock.gettimeout()
sock.settimeout(timeout)
yield sock
sock.settimeout(old_timeout)
--- end
The contextmanager decorator is an easy/quick way of making a context
manager. Everything up until the yield is executed before the 'with'
block is run, and everything after the yield is executed after the
'with' block concludes.
If the with block throws an exception, it'll be catchable at the yield
point.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/4e6fdeb6/attachment.html>
Dwayne Blind
2011-02-03 23:23:07 UTC
Permalink
The solution would be

timeout = s.gettimeout()
s.settimeout(3)
b=time.clock()
while time.clock()-b<3 :
try :
data=s.recv(1024)
except :
break
s.settimeout(timeout)

Am I right ?

Dwayne

2011/2/4 Dwayne Blind <dwayneblind at gmail.com>
Post by Dwayne Blind
Thanks Stephen. It's really nice of you.
I have not understood everything though. (I have never used a context
manager before.)
timeout = s.gettimeout() # Is that the default timeout ?
s.settimeout(3) # I guess this is a 3 second timeout
s.recv(1024)
s.settimeout(timeout) # You change it back ?
timeout = s.gettimeout()
s.settimeout(3)
b=time.clock()
data=s.recv(1024)
s.settimeout(timeout)
Am I right ?
Thanks again,
Dwayne
2011/2/3 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
Thanks for your answer. I don't want to reset my socket. I want to apply
the timeout to the rcv method only.
Setting the timeout does not "reset [your] socket", I don't think. And I
get that you want to only timeout recv... that's why I pointed out its a
socket method, not an argument to recv. If you don't want it to apply to
everything else, you just have to be sure to change it back after recv.
timeout = s.gettimeout()
s.settimeout(3)
s.recv(1024)
s.settimeout(timeout)
s.recv(1024)
--- start
from contextlib import contextmanager
@contextmanager
old_timeout = sock.gettimeout()
sock.settimeout(timeout)
yield sock
sock.settimeout(old_timeout)
--- end
The contextmanager decorator is an easy/quick way of making a context
manager. Everything up until the yield is executed before the 'with'
block is run, and everything after the yield is executed after the
'with' block concludes.
If the with block throws an exception, it'll be catchable at the yield
point.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/507256cb/attachment.html>
Dwayne Blind
2011-02-04 00:25:36 UTC
Permalink
or rather

timeout = s.gettimeout()
b=time.clock()
while time.clock()-b<3 :
s.settimeout(3-time.clock()+b)
try :
data=s.recv(1024)
except :
break
s.settimeout(timeout)

Sorry for all these messages

Dwayne


2011/2/4 Dwayne Blind <dwayneblind at gmail.com>
Post by Dwayne Blind
The solution would be
timeout = s.gettimeout()
s.settimeout(3)
b=time.clock()
data=s.recv(1024)
break
s.settimeout(timeout)
Am I right ?
Dwayne
2011/2/4 Dwayne Blind <dwayneblind at gmail.com>
Thanks Stephen. It's really nice of you.
Post by Dwayne Blind
I have not understood everything though. (I have never used a context
manager before.)
timeout = s.gettimeout() # Is that the default timeout ?
s.settimeout(3) # I guess this is a 3 second timeout
s.recv(1024)
s.settimeout(timeout) # You change it back ?
timeout = s.gettimeout()
s.settimeout(3)
b=time.clock()
data=s.recv(1024)
s.settimeout(timeout)
Am I right ?
Thanks again,
Dwayne
2011/2/3 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
Thanks for your answer. I don't want to reset my socket. I want to
apply
Post by Dwayne Blind
the timeout to the rcv method only.
Setting the timeout does not "reset [your] socket", I don't think. And I
get that you want to only timeout recv... that's why I pointed out its a
socket method, not an argument to recv. If you don't want it to apply to
everything else, you just have to be sure to change it back after recv.
timeout = s.gettimeout()
s.settimeout(3)
s.recv(1024)
s.settimeout(timeout)
s.recv(1024)
--- start
from contextlib import contextmanager
@contextmanager
old_timeout = sock.gettimeout()
sock.settimeout(timeout)
yield sock
sock.settimeout(old_timeout)
--- end
The contextmanager decorator is an easy/quick way of making a context
manager. Everything up until the yield is executed before the 'with'
block is run, and everything after the yield is executed after the
'with' block concludes.
If the with block throws an exception, it'll be catchable at the yield
point.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/6a66199f/attachment.html>
Dave Angel
2011-02-04 06:10:18 UTC
Permalink
Post by Dwayne Blind
or rather
timeout = s.gettimeout()
b=time.clock()
s.settimeout(3-time.clock()+b)
data=s.recv(1024)
break
s.settimeout(timeout)
Sorry for all these messages
Dwayne
You accidentally top-posted, so I had to delete all the history.

Without knowing anything about "s", there are two problems with this logic:

1) if you loop through the while more than once, you'll be throwing out
old data. So you might need something like data += s.recv(1024).
Conversely, if an exception happens, data is completely undefined.
Without defining a default value, your remaining code is likely to get
an exception.

2) Your time spent might vary between 3 and 6 seconds. If you need a
tighter control than that, play with the timeout a little. For example,
you might want a 1/2 second timeout, and loop until the total is 3
seconds. That way the tolerance will be 3 to 3.5 seconds.

Bonus: I don't know the behavior of the object, so I don't know what
state it's in after you timeout.

DaveA
--
--
davea at ieee.org
Stephen Hansen
2011-02-04 01:29:39 UTC
Permalink
Post by Dwayne Blind
Thanks Stephen. It's really nice of you.
I have not understood everything though. (I have never used a context
manager before.)
timeout = s.gettimeout() # Is that the default timeout ?
s.settimeout(3) # I guess this is a 3 second timeout
s.recv(1024)
s.settimeout(timeout) # You change it back ?
Yes.
I don't understand why you're doing this while loop business. Your
original question is asking for how to NOT do that, I thought. How to
use a timeout instead.

I showed you how to use a timeout instead-- now you're mixing it in with
what you originally had? Why?
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20110203/e26293ad/attachment.pgp>
Jean-Michel Pichavant
2011-02-04 10:52:06 UTC
Permalink
Post by Dwayne Blind
However I would like to set timeout on the socket rcv method, so that
the while loop stops exactly after 3 seconds. Is this possible ?
I rarely do low-level socket stuff -- [snip]
Good point. Python has a module for almost anything you would need to do
on a network. Make sure none of these modules fit your needs.
You could tell us what you want to achieve at a higher level, we may
point you to a already existing module.

Some of these modules are life saver, as I personnally always wrote
buggy netcode for whatever reason :(

JM
Dwayne Blind
2011-02-04 14:55:33 UTC
Permalink
Thanks to all of you.

@ Jean-Michel Pichavant
I am writing a small multiplayer game. Several clients are connected to the
server. Games last, say, 20 seconds.
You can think of the game as a small chat lasting 20 seconds. All the data
received by the server is sent back to the clients.

@ Stephen Hansen
Each player can send as many words as he wants. I think this is why I need
the loop. Don't you think so ?

@ Dave Angel
s = conn, with conn,address=socket.accept()
(see Socket Objects)

Thanks again

2011/2/4 Jean-Michel Pichavant <jeanmichel at sequans.com>
Post by Dwayne Blind
However I would like to set timeout on the socket rcv method, so that
the while loop stops exactly after 3 seconds. Is this possible ?
I rarely do low-level socket stuff -- [snip]
Good point. Python has a module for almost anything you would need to do on
a network. Make sure none of these modules fit your needs.
You could tell us what you want to achieve at a higher level, we may point
you to a already existing module.
Some of these modules are life saver, as I personnally always wrote buggy
netcode for whatever reason :(
JM
--
http://mail.python.org/mailman/listinfo/python-list
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/b0cf3c02/attachment.html>
Jean-Michel Pichavant
2011-02-04 15:31:15 UTC
Permalink
Post by Dwayne Blind
Thanks to all of you.
@ Jean-Michel Pichavant
I am writing a small multiplayer game. Several clients are connected
to the server. Games last, say, 20 seconds.
You can think of the game as a small chat lasting 20 seconds. All the
data received by the server is sent back to the clients.
@ Stephen Hansen
Each player can send as many words as he wants. I think this is why I
need the loop. Don't you think so ?
@ Dave Angel
s = conn, with conn,address=socket.accept()
(see Socket Objects)
Thanks again
Please do not Top post :)

xmlrpclib and Pyro are for example 2 modules that could have taken care
of your netcode. In your case, Pyro could be perfect for you since it
has no constraint (basically the xmlrpc protocol).

Quoting Pyro's home page:

"Never worry about writing network communication code again, when using
Pyro you just write your Python objects like you would normally. With
only a few lines of extra code, Pyro takes care of the network
communication between your objects once you split them over different
machines on the network. All the gory socket programming details are
taken care of, you just call a method on a remote object as if it were a
local object!".

See the examples to get better idea of remote calls with pyro.

JM
Stephen Hansen
2011-02-04 16:56:20 UTC
Permalink
Post by Dwayne Blind
@ Jean-Michel Pichavant
I am writing a small multiplayer game. Several clients are connected to
the server. Games last, say, 20 seconds.
You can think of the game as a small chat lasting 20 seconds. All the
data received by the server is sent back to the clients.
@ Stephen Hansen
Each player can send as many words as he wants. I think this is why I
need the loop. Don't you think so ?
No. I've never seen or used network code which operated in any way like
that. Sometimes you want code which blocks, sometimes you want code that
doesn't: sometimes you want stuff that may block for a little while, but
with a timeout.

I can't even imagine why you'd want code which aggressively tries to
read for multiple seconds before moving on.

Either the read works and you have data; or it doesn't, and you move on
to do something else and try again later. Perhaps after trying to read
from another socket-- or, perhaps after a select.select() call tells you
there's something more to read. T

But you need to separate the logic of your game from this network
infrastructure.

From your game logic perspective, perhaps you process the responses line
by line. From your network logic perspective, you may happen to get one
character at a time-- or it may burst to you all at once. The socket
interfaces will try to give you up to the requested number of bytes but
the network layer has every possibility of just giving you partial
responses.

So the network layer should just gather up the data as it arrives,
buffer it -- and pass it off to the game logic layer as each line is
complete (i.e., as \r\n or \n's are received). But there's no reason at
all to do a while loop to aggressively try to read from one particular
socket repeatedly for multiple seconds. At least, none that I've ever
run into.

Granted, I'm not at all a master of socket-fu.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/8c417b1b/attachment.pgp>
Dwayne Blind
2011-02-04 17:16:38 UTC
Permalink
Thank you very much Jean-Michel Pichavant and Stephen Hansen.

@ Jean-Michel Pichavant
I will have a look at Pyro.

@ Stephen Hansen
Now I am pretty much worried. :'(




2011/2/4 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
@ Jean-Michel Pichavant
I am writing a small multiplayer game. Several clients are connected to
the server. Games last, say, 20 seconds.
You can think of the game as a small chat lasting 20 seconds. All the
data received by the server is sent back to the clients.
@ Stephen Hansen
Each player can send as many words as he wants. I think this is why I
need the loop. Don't you think so ?
No. I've never seen or used network code which operated in any way like
that. Sometimes you want code which blocks, sometimes you want code that
doesn't: sometimes you want stuff that may block for a little while, but
with a timeout.
I can't even imagine why you'd want code which aggressively tries to
read for multiple seconds before moving on.
Either the read works and you have data; or it doesn't, and you move on
to do something else and try again later. Perhaps after trying to read
from another socket-- or, perhaps after a select.select() call tells you
there's something more to read. T
But you need to separate the logic of your game from this network
infrastructure.
From your game logic perspective, perhaps you process the responses line
by line. From your network logic perspective, you may happen to get one
character at a time-- or it may burst to you all at once. The socket
interfaces will try to give you up to the requested number of bytes but
the network layer has every possibility of just giving you partial
responses.
So the network layer should just gather up the data as it arrives,
buffer it -- and pass it off to the game logic layer as each line is
complete (i.e., as \r\n or \n's are received). But there's no reason at
all to do a while loop to aggressively try to read from one particular
socket repeatedly for multiple seconds. At least, none that I've ever
run into.
Granted, I'm not at all a master of socket-fu.
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/e5bea428/attachment.html>
Stephen Hansen
2011-02-04 17:30:17 UTC
Permalink
Post by Dwayne Blind
@ Stephen Hansen
Now I am pretty much worried. :'(
Why? This is all sounding like a problem that isn't actually a problem.

I think you may have over-analyzed yourself into a corner and think you
have something to solve which doesn't really need solving. :)
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 487 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20110204/0db0843a/attachment.pgp>
Dwayne Blind
2011-02-07 23:37:09 UTC
Permalink
Dear Stephen,

Thanks for telling me this all looked very peculiar. As you said, it did not
really need solving.

Cheers,
Dwayne


2011/2/4 Stephen Hansen <me+list/python at ixokai.io>
Post by Stephen Hansen
Post by Dwayne Blind
@ Stephen Hansen
Now I am pretty much worried. :'(
Why? This is all sounding like a problem that isn't actually a problem.
I think you may have over-analyzed yourself into a corner and think you
have something to solve which doesn't really need solving. :)
--
Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110208/e295452f/attachment.html>
Loading...