Socket Message Reader
ApplePhone screenMedium
A connection delivers bytes in pieces of any size. recv() returns the next piece as a list of integers from 0 to 255, and returns an empty list once the sender has closed the connection. It is provided. Pieces do not line up with messages: a piece can end in the middle of a message or contain several.
Each test builds a reader from a list of pieces and an optional max_size, then calls the methods in order. An operation that raises is recorded as the exception name, and no call is made after one that raised.
Part 1: Length-prefixed and newline-delimited reads
Implement read_message() and read_line() on top of recv(). Both keep bytes received but not yet returned in one shared buffer, so calls to the two methods may be mixed.
read_message() reads a length-prefixed message: a 4-byte big-endian unsigned length N, then N payload bytes. It returns the payload as a list of integers.
read_line() reads one newline-delimited line: a line ends at byte 10, which may be preceded by byte 13. It returns the line without its ending; a 13 directly before the 10 is removed too.
Both methods return None when the sender has closed and nothing is pending. If the sender closes in the middle of a header, a payload, or a line, the method raises EOFError.
The constructor takes max_size. read_message() raises ValueError as soon as the header announces more than max_size payload bytes. read_line() raises ValueError as soon as the bytes received show the line will be longer than max_size, not counting its ending.
- Example 1
- init
[[[0,0,0,3,7],[8,9,0,0,0,1,5]]]- operations
[["read_message",[]],["read_message",[]],["read_message",[]]]- Output
[[7,8,9],[5],null]
Why: The first piece holds the header (length 3) and one payload byte; the second piece supplies the other two bytes and the start of the next message, whose length is 1. The reader keeps the leftover bytes between calls. After the second message the sender has closed with nothing pending, so the third call returns None.
- Example 2
- init
[[[104,105,13],[10,111,10]]]- operations
[["read_line",[]],["read_line",[]],["read_line",[]]]- Output
[[104,105],[111],null]
Why: The first line is the bytes
hi; its CR arrives at the end of one piece and the LF at the start of the next, and both are dropped. The second line iso. Then the sender has closed with nothing pending, so None.
Constraints
1 <= len(chunks) <= 10^6total bytes across all pieces0 <= max_size <= 10^6- Every piece
chunk[i]is non-empty - Each
chunk[i]holds integers with0 <= chunk[i][j] <= 255 - No
read_messageorread_linecall is made after a call that raised