<table cellspacing="0" cellpadding="0" border="0" ><tr><td valign="top" style="font: inherit;"><DIV>This may not be the correct list for this issue, if so I would appreciate if anyone could forward it to the correct list.</DIV>
<DIV> </DIV>
<DIV>I had experienced a number of problems with standard library SocketServer when implementing a tcp forking server under python 2.6. I fixed every issue including some timing problems (e.g. socket request closed too fast before the last packet was grabbed) by overriding or extending methods as needed.</DIV>
<DIV> </DIV>
<DIV>Nonetheless, the one issue which may require a wider attention had to deal with method </DIV>
<DIV>collect_children() of class TCPServer. This method makes the following os library call:</DIV>
<DIV> </DIV>
<DIV>pid, result = os.waitpid(child, options=0)</DIV>
<DIV> </DIV>
<DIV>Under some conditions the method breaks on this line with a message indicating that an unexpected keyword argument "options" was provided. In a continuous run reading thousands of packets from multiple client connects, this line seems to fail at times, but not always. Unfortunately, I did not record the specific conditions that caused this "erroneous" error message, which happened unpredicatbly multiple times.</DIV>
<DIV> </DIV>
<DIV>To correct the problem the line of code may be changed by removing the keyword to:</DIV>
<DIV> </DIV>
<DIV>pid, result = os.waitpid(child, 0); this never fails.</DIV>
<DIV> </DIV>
<DIV>Nonetheless, I believe that method collect_children() is too cumbersome as written and I did override it with the following simpler strategy. The developers of SocketServer may want to consider it as a replacement to the current code used for collect_children().</DIV>
<DIV> </DIV>
<DIV> def collect_children(self):<BR> '''Collect Children - Overrides ForkingTCPServer collect_children method.<BR> The provided method in SocketServer modules does not properly work for the<BR> intended purpose. This implementation is a complete replacement.<BR> <BR> Each new child process id (pid) is added to list active_children by method<BR> process_request(). Each time a new connection is created by the method, a<BR> call is then made here for cleanup of any inactive processes.</DIV>
<DIV> Returns: None<BR> '''<BR> child = None<BR> try:<BR> if self.active_children: # a list of active child processes<BR> for child in self.active_children:<BR> try:<BR> val = os.waitpid(child, os.WNOHANG) # val = (pid, status)<BR> if not val[0]: # pid 0; child is inactive<BR> time.sleep(0.5) # wait to kill<BR> os.kill(child, signal.SIGKILL) # make sure it is
dead<BR> self.active_children.remove(child) # remove from active list<BR> else: continue<BR> except OSError, err:<BR> if errno.ECHILD != err.errno: # do not report; child not found<BR> msg = '\tOS error attempting to terminate child process {0}.'<BR> self.errlog.warning(msg.format(str(child)))<BR> else: pass<BR> except:<BR> msg = '\tGeneral error attempting to terminate child process {0}.'<BR> self.errlog.exception(msg.format(str(child)))<BR> else:
pass # for child loop<BR> else: pass<BR> except:<BR> msg = '\tGeneral error while attempting to terminate child process {0}.'<BR> self.errlog.exception(msg.format(str(child)))<BR></DIV>
<DIV>Things to note are:</DIV>
<DIV>1. Using os.WNOHANG instead of 0 as options values to os.waitpid</DIV>
<DIV>2. Detecting if we get a returned pid==0; hence assume child is done</DIV>
<DIV>3. Attempt a os.kill for defunct children after a time.sleep(0.5); allow dependent processes to complete their job before totally closing down the request.</DIV>
<DIV>4. Report os errors as exceptions; but not errno.ECHILD, which means trying to kill none existing child; keep this as a warning.</DIV>
<DIV>This is more suscinct code and does the job. At least it does it for me.</DIV>
<DIV> </DIV>
<DIV>Thanks,</DIV>
<DIV>Boris</DIV>
<DIV> </DIV></td></tr></table><br>