Skip to content
Advertisement

Creating multiple tcp socket handlers from one class in Python

Is it possible in Python3 to create a TCP Socket handler class that can have multiple unique instances?

I have 2 threaded TCP Socket servers that are providing unique information to the connected client. I am trying to make it so that ‘node 1’ socket server handler will provide only the data for ‘node 1’ while ‘node 2’ socket server handler will provide on the data for ‘node 2’.

I have made a custom handler with the variable ‘node’.

class NodeTCPHandler(socketserver.BaseRequestHandler):

    def __init__(self, request, client_address, server):
        socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
        self.node = 6
        return
    
    def handle(self):
        logging.debug("Node Socket has been started")
        global stop, temperature, humidity, pressure, voltage
        
        logging.debug("{} connected to Node 0{} Socket".format(self.client_address[0], self.node+1))
        
        while not stop:
            msg = (str(temperature[self.node])+','+str(humidity[self.node])+','+str(pressure[self.node])+','+str(voltage[self.node]))
            self.request.sendall(msg.encode())
            time.sleep(5)

I have tried to set the variable ‘node’ after creating the socket server and defining the handler.

node_01_server = socketserver.TCPServer((hostAddr, nodePort[0]), NodeTCPHandler)
node_01_server.RequestHandlerClass.node = 0
node_02_server = socketserver.TCPServer((hostAddr, nodePort[1]), NodeTCPHandler)
node_02_server.RequestHandlerClass.node = 1

node_01_thread = threading.Thread(name='Node 01 Socket',target=node_01_server.serve_forever)
node_02_thread = threading.Thread(name='Node 02 Socket',target=node_02_server.serve_forever)

This is close to working, but when I set the ‘node_02_server.RequestHandlerClass.node’ it over writes the ‘node_01_server.RequestHandlerClass.node’ node variable as well!

I am obviously missing something but I feel I am close to a solution. This is my first real attempt at using classes and socket servers so if I have made any obvious mistakes please let me know.

Advertisement

Answer

Line node_01_server.RequestHandlerClass.node = 0 sets class attribute RequestHandlerClass.node, not instance attribute which it seems you would like to change. And since there can be only one class attribute node of the class RequestHandlerClass it is updated on each such line.

Let’s consider a couple of ways to separate your handlers:

  1. Implement several NodeTCPHandler and pass the right one into TCPServer

    class BaseNodeTCPHandler(socketserver.BaseRequestHandler):
        NODE_TYPE = 6
    
        def __init__(self, *args, **kwargs):
            self.node = self.NODE_TYPE
            super().__init__(*args, **kwargs)
    
    class Node0TCPHandler(BaseNodeTCPHandler):
        NODE_TYPE = 0
    
    class Node1TCPHandler(BaseNodeTCPHandler):
        NODE_TYPE = 1
    

    and now you can pass those Node0TCPHandler/Node1TCPHandler into an appropriate server

    node_01_server = socketserver.TCPServer((hostAddr, nodePort[0]), Node0TCPHandler)
    node_02_server = socketserver.TCPServer((hostAddr, nodePort[1]), Node1TCPHandler)
    
  2. Implement custom TCPServer which can take additional arguments and pass them into the handler’s constructor

    class NodeTCPHandler(socketserver.BaseRequestHandler):
    
        def __init__(self, node, *args, **kwargs):
            self.node = node
            super().__init__(*args, **kwargs)
    
    class CustomTCPServer(socketserver.TCPServer):
    
        def __init__(self, *args, node=6, **kwargs):
            super().__init__(*args, **kwargs)
            self.node = node
    
        def finish_request(self, request, client_address):
            """Finish one request by instantiating RequestHandlerClass."""
            self.RequestHandlerClass(self.node, request, client_address, self)
    
    

    and now you can instantiate servers with different node values like that:

    node_01_server = CustomTCPServer((hostAddr, nodePort[0]), NodeTCPHandler, node=0)
    node_02_server = CustomTCPServer((hostAddr, nodePort[1]), NodeTCPHandler, node=1)
    

The first approach is better since it requires fixes in a smaller number of classes, especially if more similar updates are coming.

Advertisement