1

I'm confused as to how to send a variable to a TCPHandler using SocketServer.TCPServer in python..

HOST, PORT = hosts[0], args.port
server = SocketServer.TCPServer((HOST, PORT), METCPHandler)
server.serve_forever()

Which calls:

class METCPHandler(SocketServer.BaseRequestHandler):           
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print "{} wrote:".format(self.client_address[0])
        r = MExpressHandler(self.data, False)

But I want to pass a debug boolean to MExpressHandler.. so

HOST, PORT = hosts[0], args.port
server = SocketServer.TCPServer((HOST, PORT), METCPHandler(debug))
server.serve_forever()

Fails. Whats the correct way of doing this? Do I have to recreate a whole TCPHandler over-ridding __init__?

A. Rodas
  • 20,171
  • 8
  • 62
  • 72
willwade
  • 1,998
  • 2
  • 16
  • 22
  • Look at this, it's a duplication to http://stackoverflow.com/questions/6875599/with-python-socketserver-how-can-i-pass-a-variable-to-the-constructor-of-the-han – MostafaR Apr 08 '13 at 21:29

2 Answers2

4

Trust your instincts, the correct way is indeed to subclass TCPServer and override the __init__ method, but Python makes this very easy!

import SocketServer

class DebugTCPServer(SocketServer.TCPServer):
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True, debug=True):
        self.debug = debug
        SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)

class DebugMETCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        # self.server is an instance of the DebugTCPServer
        DEBUG = self.server.debug
        self.data = self.request.recv(1024).strip()
        if DEBUG:
            print "{} wrote:".format(self.client_address[0])
        r = MExpressHandler(self.data, False)


server = DebugTCPServer((HOST, PORT), DebugMETCPHandler, debug=True)

or since we specified debug=True as the default:

server = DebugTCPServer((HOST, PORT), DebugMETCPHandler)
phoenix
  • 7,988
  • 6
  • 39
  • 45
John
  • 375
  • 2
  • 7
  • thanks! I'm getting a NameError: name 'TCPServer' is not defined. Do I have to define the whole thing somehow? Sorry for being dim.. – willwade Apr 08 '13 at 22:02
  • Make sure you import it "from SocketServer import TCPServer" or reference it like "SocketServer.TCPServer" – John Apr 08 '13 at 22:07
  • The prob is on the `class DebugMETCPHandler(SocketServer.BaseRequestHandler):` line. Should that be something different..? `class DebugMETCPHandler(DebugTCPServer.BaseRequestHandler):` I wondered but no joy – willwade Apr 08 '13 at 22:27
  • I didn't notice TCPServer is an old-style class, which means we can't call super, instead you call the init methods of the base class directly – John Apr 08 '13 at 22:54
  • thanks John_GG. Still causing the same error though.. `class DebugTCPServer(SocketServer.TCPServer):` no matter how the SocketServer is imported (e.g. from SocketServer import *). (To be more precise 'NameError: name 'SocketServer' is not defined') – willwade Apr 08 '13 at 23:07
  • To use my code, you must import the SocketServer module with this command `import SocketServer`. Then any time you use a class from that module, you must reference it by prepending the SocketServer module name, ie, `SocketServer.TCPServer` or `SocketServer.UDPServer`. The modules that we subclassed, are defined in your module's namespace so we reference them with just their class name, e.g., `DebugMETCPHandler`, or `DebugTCPServer` – John Apr 08 '13 at 23:24
  • Ahh I was being an idiot as to be expected. Thanks John. A hero. – willwade Apr 08 '13 at 23:32
  • Note that in Python 3 `SocketServer` was renamed to `socketserver` for PEP 8 compliance. See [socketserver docs](https://docs.python.org/3.5/library/socketserver.html) – phoenix Jul 29 '15 at 14:33
0

As I proposed in this post already, it is possible to do it without sub-classing the TCPServer. It is in fact more concise and generic.

You can give parameters to your handler this way:

class METCPHandler(SocketServer.BaseRequestHandler):
  def __init__(self, debug):
    self.debug = debug

  def __call__(self, request, client_address, server):
    h = METCPHandler(self.debug)
    SocketServer.StreamRequestHandler.__init__(h, request, client_address, server)

You can now give an instance of your handler to the TCPServer:

SocketServer.TCPServer((HOST, PORT), METCPHandler(True))

The TCPServer normally creates a new instance of METCPHandler per request but in this case, the __call__ method will be called instead of the constructor (it is already an instance.)

In the call method, I explicitly make a copy of the current METCPHandler and pass it to the super constructor to conform to the original logic of "one handler instance per request".

It is worth having a look at the SocketServer module to understand what happens here: https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

ant1g
  • 969
  • 9
  • 13