1254 Chapter 61
61.1 Partial Reads and Writes on Stream Sockets
When we first introduced the read() and write() system calls in Chapter 4, we noted
that, in some circumstances, they may transfer fewer bytes than requested. Such
partial transfers can occur when performing I/O on stream sockets. We now con-
sider why they can occur and show a pair of functions that transparently handle
partial transfers.
A partial read may occur if there are fewer bytes available in the socket than were
requested in the read() call. In this case, read() simply returns the number of bytes avail-
able. (This is the same behavior that we saw with pipes and FIFOs in Section 44.10.)
A partial write may occur if there is insufficient buffer space to transfer all of
the requested bytes and one of the following is true:
z A signal handler interrupted the write() call (Section 21.5) after it transferred
some of the requested bytes.
z The socket was operating in nonblocking mode (O_NONBLOCK), and it was possible
to transfer only some of the requested bytes.
z An asynchronous error occurred after only some of the requested bytes had
been transferred. By an asynchronous error, we mean an error that occurs asyn-
chronously with respect to the application’s use of calls in the sockets API. An
asynchronous error can arise, for example, because of a problem with a TCP
connection, perhaps resulting from a crash by the peer application.
In all of the above cases, assuming that there was space to transfer at least 1 byte,
the write() is successful, and returns the number of bytes that were transferred to the
output buffer.
If a partial I/O occurs—for example, if a read() returns fewer bytes than
requested or a blocked write() is interrupted by a signal handler after transferring
only part of the requested data—then it is sometimes useful to restart the system
call to complete the transfer. In Listing 61-1, we provide two functions that do this:
readn() and writen(). (The ideas for these functions are drawn from functions of the
same name presented in [Stevens et al., 2004].)
The readn() and writen() functions take the same arguments as read() and write().
However, they use a loop to restart these system calls, thus ensuring that the
requested number of bytes is always transferred (unless an error occurs or end-of-
file is detected on a read()).
#include "rdwrn.h"
ssize_t readn(int fd, void *buffer, size_t count);
Returns number of bytes read, 0 on EOF, or –1 on error
ssize_t writen(int fd, void *buffer, size_t count);
Returns number of bytes written, or –1 on error