Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to pass arguments to TCPServer handler class

Here’s a piece of experimental/educational code written solely to "play" with socketserver functionality.

The code works without error. All it does is open and read a file sending the file’s contents over a TCP connection to a TCPServer. The server prints the received data during the overridden handle() function of BaseRequestHandler.

from socket import socket, AF_INET, SOCK_STREAM
from socketserver import BaseRequestHandler, TCPServer
from threading import Thread

HOST = "localhost"
PORT = 10101
ADDR = HOST, PORT
RECVBUF = 4096
SENDBUF = RECVBUF // 2
INPFILE = "inputfile.txt"


class MyHandler(BaseRequestHandler):
    def handle(self):
        while data := self.request.recv(RECVBUF):
            print(data.decode(), end="")


def server(tcpserver: TCPServer):
    tcpserver.serve_forever()


if __name__ == "__main__":
    with open(INPFILE, "rb") as indata:
        with TCPServer(ADDR, MyHandler) as tcpserver:
            (t := Thread(target=server, args=[tcpserver])).start()
            with socket(AF_INET, SOCK_STREAM) as s:
                s.connect(ADDR)
                while chunk := indata.read(SENDBUF):
                    s.sendall(chunk)
            tcpserver.shutdown()
            t.join()

So this is fine but what if I want the handle() function to write the received data to a file? Sure, I could hard-code the filename into the handle() function or maybe even make it globally available. Neither of those options seem particularly Pythonic to me.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The TCPServer is constructed based on a RequestHandler type – i.e., not a class instance. What I really want to be able to do is (somehow) pass a filename into the MyHandler class. The TCPServer instance will (presumably) have an internal instance variable for the constructed MyHandler but that’s not documented so I don’t know where that is.

Maybe I’m missing something fundamental but I just can’t figure out the "right" way to do achieve this

>Solution :

One way of getting around this API limitation is to use class factory function:

def get_handler(fname):
    class MyHandler(BaseRequestHandler):
        def handle(self):
            while data := self.request.recv(RECVBUF):
                print(data.decode(), end="")
                # copy it to file, I dunno =)
                with open(fname, 'wb') as f:
                    f.write(data)
    return MyHandler

Then use it like that:

    with TCPServer(ADDR, get_handler('/tmp/file.bin')) as tcpserver:
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading