Build a framed message server
A connection is a stream of bytes with no edges in it. Four bytes of length and then the payload put the edges back: a parser, then a buffer per connection that survives any cut, then an event loop that bounds what a hostile or slow peer can make it hold.
Why does a TCP server need framing at all?
Because a stream socket delivers bytes, not messages. Two sends of 6 bytes each can arrive as one read of 12, or as reads of 2, 9 and 1, and nothing in the bytes says where one message ended. Framing is the rule both sides agree on for finding the edges again. The common choices are a fixed size, a delimiter such as a newline, or a length written in front of each message. A length prefix is the one that handles any payload, including one that contains the delimiter, and it lets the reader know how much to wait for before it has seen the body.
What does recv return when the peer closes the connection?
An empty bytes object. The Python documentation says a returned empty bytes object indicates that the client has disconnected. So an empty read is not an error and not data: it is the end of the stream. What the server does next depends on its buffer. If it holds nothing, the peer closed between frames and the connection can be closed once any queued replies are out. If it holds part of a frame, the peer closed in the middle of one, and the partial frame is dropped with the connection.
Why check the length against a limit before reading the payload?
Because the length is written by the other side, and the other side may be broken or hostile. A header of ff ff ff ff promises a payload of 4294967295 bytes. A reader with no limit files that promise and keeps every byte that arrives while it waits, so one connection can make the server hold as much memory as it cares to send. Checking the length the moment it is read refuses the frame before any of its body is kept. The build records the unbounded reader holding 12 bytes of an expected 4294967299 on a three-read input, still waiting.
What does backpressure mean in a server like this?
It means a peer that does not read its replies stops being read. Every request the server reads adds a reply to that connection’s outgoing queue, and if the peer never takes the replies, the queue grows as fast as the peer can send. Here the server asks to read a connection only while its queue is under a set number of bytes, the backlog. Past that it only tries to write. The requests the peer keeps sending stay in the kernel’s buffers, which are bounded, and the kernel slows the sender down. The queue can pass the backlog by the replies to one read, and no further.
Is this round taken in Python?
Usually not. A round like this is normally taken in C, C++, Rust or Go, over real sockets. The mechanism is the same in Python, because the socket module is a thin layer over the same system calls: the documentation calls it a straightforward transliteration of the Unix system call and library interface for sockets. What changes in a systems language is what you manage by hand, such as the buffer’s memory, and what the interviewer listens for: every partial result handled, and every buffer bounded.