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.
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
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: