Search code examples
pythonsocketstcpstreamtcpserver

Custom newline chracter in python socketserver.StreamRequestHandler


I'm implementing a socket server for python. Ideally I would use a socketserver.TCPServer in combination with thereadline-functionality of socketserver.StreamRequestHandler, see for instance the example in the documentation. Unfortunaltely I have to use a custom newline character other than \n.

Is there a way to change this newline character in this context? Accoding to my debugger the rfile-attribute of socketserver.StreamRequestHandler, is a _io.BufferedReader-object but I couldn't find any documentation about that.


Solution

  • No, there is not a way to change the newline character. rfile is an io.BufferedReader which is a buffered binary stream which inherits the readline() method from io.IOBase (emphasis mine)

    readline(size=-1, /)
    Read and return one line from the stream. If size is specified, at most size bytes will be read.

    The line terminator is always b'\n' for binary files; for text files, the newline argument to open() can be used to select the line terminator(s) recognized.

    You can buffer your own fixed reads and extract messages using your own newline character(s) with code like the following:

    import socketserver as ss
    import threading
    import socket
    
    class MyTCPHandler(ss.StreamRequestHandler):
    
        _buffer = b''
        LINEEND = b'xy'
    
        def handle(self):
            while True:
                line = self.read_until(self.LINEEND)
                if not line: break
                print(line)
    
        def read_until(self, terminator):
            while terminator not in self._buffer:
                chunk = self.request.recv(1024)
                if not chunk: break
                self._buffer += chunk
            msg, _, self._buffer = self._buffer.partition(terminator)
            return msg
    
    def server():
        with ss.ThreadingTCPServer(('', 5000), MyTCPHandler) as server:
            server.serve_forever()
    
    threading.Thread(target=server, daemon=True).start()
    
    # client 1
    with socket.socket() as client1, socket.socket() as client2:
        client1.connect(('localhost', 5000))
        client2.connect(('localhost', 5000))
    
        client1.sendall(b'client 1 message 1xyclient 1')
        client2.sendall(b'client 2 message 1xyclient 2')
        client1.sendall(b' message 2xyclient 1 message 3xy')
        client2.sendall(b' message 2xyclient 2 message 3xy')
    

    Output:

    b'client 1 message 1'
    b'client 2 message 1'
    b'client 1 message 2'
    b'client 2 message 2'
    b'client 1 message 3'
    b'client 2 message 3'