Files, sockets, and partial results

A read hands back the bytes that have arrived, which can be fewer than you asked for, and a write can take part of what you give it. Every loop on this page exists because of that, and every run of it here was recorded by the build.

Does os.read always return the number of bytes I asked for?

No. The Python documentation says os.read reads “at most n bytes”, and socket.recv takes the most it will return at once. A pipe or a socket hands back what has arrived so far, so a 7-byte message can come back as 2, then 3, then 2. An empty result means the other end has closed, not that nothing has arrived yet. Code that needs n bytes calls read in a loop until it has them, and treats an empty read before then as an error.

What is the difference between socket.send and socket.sendall?

send returns the number of bytes it sent, and the documentation says applications are responsible for checking that all data has been sent. sendall keeps sending until everything is sent or an error occurs, and returns None. What sendall cannot tell you is how far it got when it fails: the documentation says there is then no way to determine how much data, if any, was successfully sent. For os.write there is no sendall, so you write the loop yourself.

What is the difference between a hard link and a symbolic link?

A hard link is a second name for the same inode, the record that holds a file’s data and metadata. Both names are equal: removing one leaves the other working, and st_nlink counts how many there are. A symbolic link is a small file that holds a path. Removing the file it names leaves the symlink holding a path to nothing, and st_nlink on the file never counted it.

Does flush() write my data to disk?

No. flush moves bytes out of the Python file object’s buffer into the operating system with a write system call, and from there any other reader of the file can see them. They are then in the kernel’s page cache, in memory. os.fsync is the call the Python documentation describes as forcing a write to disk. A program that has to survive a power cut calls flush and then fsync before it tells anyone the data is safe.

What does select do, and why use non-blocking sockets with it?

select, or selectors.DefaultSelector in Python, waits until at least one of many descriptors can be read or written without blocking, and says which. A loop around it can serve many connections from one thread: it reads only what is ready, so a quiet client never holds up a busy one. The descriptors are set non-blocking so that a read which would have to wait raises BlockingIOError instead of stopping the whole loop.