Yes, but it's still how the overwhelming majority of network code functions. It's not really till the rise of libev/libuv and friends that people start moving to non-blocking as a default (I spent pretty much an entire year of my life convincing an AWS team to reclaim 4 GB of thread stacks by moving to non-blocking I/O).
>> or return an "incomplete message" error meaning that the caller is the one to continue reading.
> That's pretty un-user-friendly.
It's also how all non-blocking I/O worked prior to languages adding native async functionality.