How do I modify variables in the SocketServer server instance from within a RequestHandler handler instance in Python?

StackOverflow https://stackoverflow.com/questions/3868132

Question

Here's the code in question:

  class Server(SocketServer.ForkingMixIn, SocketServer.TCPServer):
     __slots__ = ("loaded")

  class Handler(SocketServer.StreamRequestHandler):
     def handle(self):
        print self.server.loaded # Prints "False" at every call, why?
        self.server.loaded = True
        print self.server.loaded # Prints "True" at every call, obvious!

  server = Server(('localhost', port), Handler)
  server.loaded = False

  while True:
     server.handle_request()

Every time a new request comes in, the output I get is False followed by True. What I want is False followed by True the first time, and True followed by True henceforth.

Why aren't the modifications I made to the variable in the server instance persisting outside the scope of the handler's handle() function?

UPDATED:

So, I try using global variables to achieve what I want:

  loaded = False

  class Server(SocketServer.ForkingMixIn, SocketServer.TCPServer):
     pass

  class Handler(SocketServer.StreamRequestHandler):
     def handle(self):
        global loaded
        print loaded # Prints "False" at every call still, why?
        loaded = True
        print loaded # Prints "True" at every call, obvious!

  def main():
     server = Server(('localhost', 4444), Handler)
     global loaded
     loaded = False

     while True:
        server.handle_request()

  if (__name__ == '__main__'):
     main()

And it still doesn't work, i.e. produces the same output as before. Could anyone please tell me where I'm going wrong?

Was it helpful?

Solution

Forking creates a new process, so you can't modify the server's variables in the original process. Try the ThreadingTCPServer instead:

import SocketServer

class Server(SocketServer.ThreadingTCPServer):
    __slots__ = ("loaded")

class Handler(SocketServer.StreamRequestHandler):
    def handle(self):
        self.server.loaded = not self.server.loaded
        print self.server.loaded # Alternates value at each new request now.

server = Server(('localhost',5000),Handler)
server.loaded = False

while True:
    server.handle_request()

OTHER TIPS

Your problem is that SocketServer.ForkingMixin creates a new process for every request. Therefore, every time a new request comes in all your variables get reset to their default state. So essentially no matter what you assign to self.server.loaded it will get reset at the next request. This is also why globals won't work.

If you need a variable to persist between requests you'd best write that data somewhere more, er, persistent =). Essentially, it sounds like you're trying to solve the problem of keeping session variables. There's a million and one ways to do it and depending on your situation, one way might be more pertinent than another. I highly recommend looking at how other Python-based SocketServer applications do it.

Just do a quick google for similar code to yours: "filetype:py SocketServer ForkingMixIn" (one of the first results is CherryPy which I highly recommend looking at).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top