SocketServer crash on my machine

xtian at hyperactive.co.nz xtian at hyperactive.co.nz
Fri Jun 29 08:11:03 CEST 2001


On 28 Jun 2001 00:42:06 GMT, gmcm at hypernet.com (Gordon McMillan)
wrote:

>Syver Enstad wrote: 
>
>>I was checking out the the SocketServer example in Mark Lutz rather
>>excellent book Programming Python 2 edition,
>>when
>
>[snip] 
>
>>    data = self.request.recv(1024)
>>  File "<string>", line 1, in recv
>>AttributeError: 'int' object has no attribute 'recv'
>
>The socket has already been closed.
>
>[more snippage]
>
>>class MyClientHandler(SocketServer.BaseRequestHandler):
>>    def handle(self):
>>        print self.client_address, now()
>>        print self.request
>>        time.sleep(5)
>>        while 1:
>>            data = self.request.recv(1024)
>>            if not data:
>>                break
>>            self.request.send('Echo=>%s at %s' % (data, now()))
>>        self.request.close()
>
>The code is wrong. It assumes that it is in charge of closing the
>socket (or that a closed socket will yield no data - which is just
>one way that you may find out a socket is closed).

Actually, this problem is caused by a bug in the SocketServer module
- the ThreadingMixin class overriding the process_request method means
that the ThreadingTCPServer.process_request() call returns as soon as
the Thread.start() call completes (instead of waiting for the request
to be handled as it would in a single thread). Then the handle_request
method on BaseServer closes the socket, which really should be closed
by the RequestHandler in this case (because there's no way for the
server to know when the thread finishes).

It was quite confusing when I got bitten by it, because (due to the
vagaries of thread scheduling) the error was occurring sometimes in
the recv() call and sometimes at the send(). That error message
doesn't help, although I guess that's happening at the OS level..

I fixed it by overriding handle_request like so:

    def handle_request(self):
        """Handle one request, possibly blocking."""
        try:
            request, client_address = self.get_request()
        except socket.error:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except:
                self.handle_error(request, client_address)
                self.close_request(request)

So handle_request won't close the socket unless it gets an
exception... 

And made sure the RequestHandler.handle method has a try... finally
block which closes the socket.

More info at SourceForge:
http://sourceforge.net/tracker/index.php?func=detail&aid=417845&group_id=5470&atid=105470

HTH,
Xtian



More information about the Python-list mailing list