[Python-Dev] Re: Integrating timeoutsocket.py

Bernard Yue bernie@3captus.com
Sat, 27 Apr 2002 23:56:25 -0600


Michael Gilfix wrote:
> 
>   Gonna carbon the dev list to get people's opinions on this
> one. Something definitely needs to change in the way ServerSocket.py
> is implemented.
>
>   Found the cause in ServerSocket.py. You need to add the line:
> 
>     t.setDaemon (1)
>

This looks like a simple and decent proposal. When you do a keyboard
interrupt over the server you are intended to interrupt the main thread
(in this situation under Linux the interrupt always sends to the main
thread).  I think you should just summit a patch.  At worst it will just
be rejected.

Under python 2.1, the keyboard interrupt will trigger an exception
'error' in one of the thread and the whole program exit (so serve the
propose of interrupt).  Behavior actually changed to current status
since python 2.2.

Is the change by design or by accident?
 
>   at line 469 in ServerSocket.py, right after the thread is
> created. Whether this is an error is debatable though. The problem
> is that the other threads don't know you're exiting, so they
> continue running after you exit. Ideally, we should either just set
> the client threads as daemon threads or we should have some way of
> signaling them that they must terminate. One solution without touching
> ServerSocket is to subclass off of ThreadingMixIn and create a new
> ThreadingTCPServer class.  Not too elegant though.
> 
>   The docs for the thread module say:
> 
> "Threads interact strangely with interrupts: the KeyboardInterrupt
> exception will be received by an arbitrary thread. (When the signal
> module is available, interrupts always go to the main thread.)"
> 
>   Kinda unfortunate in this scenario.
> 
>                     -- Mike
> 
> On Sat, Apr 27 @ 12:44, Bernard Yue wrote:
> > About the test.  I am facing this problem with Threading server (using
> > SocketServer module).
> > The new socket module somehow change the behavior of the threading
> > server.  The change happens during server exit.
> >
> > With the old module, when there is are client(s) connected to the
> > server, existing the server by KeyboardInterrupt will close the
> > connection with all the connecting client.  Not the case for the new
> > module.  The thread which serving a connected client will stays on until
> > the client exit.
> >
> > I am not exactly sure why it happens.  Attached is the script, use
> > telnet client to do the test and see if you can figure out why.
> >
> >
> >
> > Bernie
> > ===================================================================
> >
> #!/usr/bin/env python
> '#!/home/bernie/src/python23/dist/src/python'
> 
> import time
> import select
> import SocketServer
> 
> class RequestHandler( SocketServer.StreamRequestHandler):
>     def __init__(self, request, client_address, server):
>         SocketServer.StreamRequestHandler.__init__(self,
>                 request, client_address, server)
> 
>     def handle( self):
>         """Handle a client"""
>         _remote_id = '%s:%s' % self.request.getpeername()
>         print 'Client %s connected' % _remote_id
>         self.wfile.write( 'Hello %s\n' % _remote_id)
> 
>         while 1:
>             select.select( [self.rfile.fileno()], [], [])
>             try:
>                 _in = self.rfile.readline()
>                 if not self.process_command( _in, _remote_id):
>                     break
>             except IOError:
>                 break    # connection reset by requester
> 
>         print '%s quited' % _remote_id
> 
>     def process_command( self, command, client='anonymous'):
>         _command = command.strip()
>         if _command == 'exit' or not command:
>             return 0
> 
>         if _command:
>             print 'Request from %s: [%s]' % (client, _command)
>             self.wfile.write( 'Command [%s] received!\n' % _command)
>             self.wfile.flush()
> 
>         return 1
> 
> class MyTCPServer( SocketServer.TCPServer):
>     def __init__( self, server_address, RequestHandlerClass, timeout=None):
>         self.__timeout = timeout
>         SocketServer.TCPServer.__init__( self, server_address,
>                 RequestHandlerClass)
> 
>         '''
>         # set timeout
>         if self.__timeout:
>             try:
>                 print 'Set timeout to %s second(s)' % self.socket.gettimeout()
>                 print 'Current time is %s' % time.asctime()
>                 self.socket.settimeout( self.__timeout)
>             except AttributeError:
>                 print 'No timeout with socket'
>         '''
> 
> class ThreadingTCPServer( SocketServer.ThreadingMixIn, MyTCPServer): pass
> 
> def main( argv):
>     if len(argv) == 1:
>         print 'Usage server.py <IP address> <port>'
>         return 0
> 
>     _address = ( argv[1], int(argv[2]))
>     _server = ThreadingTCPServer( _address, RequestHandler, 3)
> 
>     try:
>         _server.serve_forever()
>     except KeyboardInterrupt:
>         _server.server_close()
>         print "Server Terminated!"
> 
> 
> if __name__ == "__main__":
>     import sys
>     main( sys.argv)
> 
> --
> Michael Gilfix
> mgilfix@eecs.tufts.edu
> 
> For my gpg public key:
> http://www.eecs.tufts.edu/~mgilfix/contact.html
> 
> _______________________________________________
> Python-Dev mailing list
> Python-Dev@python.org
> http://mail.python.org/mailman/listinfo/python-dev

-- 
There are three schools of magic.  One:  State a tautology, then ring
the changes on its corollaries; that's philosophy.  Two:  Record many
facts.  Try to find a pattern.  Then make a wrong guess at the next
fact; that's science.  Three:  Be aware that you live in a malevolent
Universe controlled by Murphy's Law, sometimes offset by Brewster's
Factor; that's engineering.
                -- Robert A. Heinlein