select.select and socket.setblocking

Francesco Bochicchio bockman at virgilio.it
Tue Dec 30 19:19:08 CET 2008


Laszlo Nagy ha scritto:
> I'm using this method to read from a socket:
> 
>    def read_data(self,size):
>        """Read data from connection until a given size."""
>        res = ""
>        fd = self.socket.fileno()
>        while not self.stop_requested.isSet():
>            remaining = size - len(res)
>            if remaining<=0:
>                break
>            # Give one second for an incoming connection so we can stop the
>            # server in seconds when needed
>            ready = select.select([fd], [], [], 1)
>            if fd in ready[0]:
>                data = self.socket.recv(min(remaining,8192)) # 8192 is
> recommended by socket.socket manual.
>                if not data:
>                    # select returns the fd but there is no data to read
> -> connection closed!
>                    raise TransportError("Connection closed.")
>                else:
>                    res += data
>            else:
>                pass
>        if self.stop_requested.isSet():
>            raise SystemExit(0)
>        return res
> 
> 
> This works: if I close the socket on the other side, then I see this in
> the traceback:
> 
>  File "/usr/home/gandalf/Python/Projects/OrbToy/orb/endpoint.py", line
> 233, in read_data
>    raise TransportError("Connection closed.")
> TransportError: Connection closed.
> 
> Also when I call stop_requested.set() then the thread stops within one
> seconds.
> 
> Then I switch to non blocking mode, my code works exactly the same way,
> or at least I see no difference.
> 
> I have read the socket programming howto (
> http://docs.python.org/howto/sockets.html#sockets ) but it does not
> explain how a blocking socket + select is different from a non blocking
> socket + select. Is there any difference?
> 
> Thanks
> 
Couple of remarks:

1. AFAIK, select in python accepts also socket objects, or anything 
which has a fileno() method returning an integer. So you don't need to 
extract the fileno from the socket (python will do for you) although it 
does no harm.

2. IMO, the behaviour of your code is correct: with TCP protocol, when 
the remote ends disconnects, your end receives a 'read event' without 
data; you should just handle the fact that recv returns nothing as 
normal, not as error, and close your end of the connection.

If you are interested in socket errors, you should
also fill the third 'fd-set' in the select call, and after select 
returns check that fd is not in it anymore:

ready = select.select( [fd],[], [fd] )
if fd in ready[2]:
    # raise your error here

3. AFAIK (sorry, I feel acronym-ly today ;), there is no difference in 
select between blocking and non-blocking mode. The difference is in the
recv (again, assuming that you use TCP as protocol, that is AF_INET, 
SOCK_STREAM), which in the blocking case would wait to receive all the 
bytes that you requested, or the disconnection, in the other case would 
return immediately (and you should check the number of returned bytes, 
and when you read the remaining bytes of the message put the pieces 
together). I myself tend to avoid using non-blocking sockets, since 
blocking sockets are much easier to handle...

HTH

Ciao
------
FB



More information about the Python-list mailing list