Stream sockets (e.g., TCP sockets) exhibit a behavior with the read and write
functions that differs from normal file I/O. A read or write on a stream socket might
input or output fewer bytes than requested, but this is not an error condition. The
reason is that buffer limits might be reached for the socket in the kernel. All that is
required to input or output the remaining bytes is for the caller to invoke the read or
write function again. Some versions of Unix also exhibit this behavior when writing
more than 4,096 bytes to a pipe. This scenario is always a possibility on a stream socket with read, but is normally seen with write only if the socket is nonblocking. Nevertheless, we always call our writen function instead of write, in case the implementation returns a short count.
#include "unp.h"
ssize_t readn(int filedes, void *buff, size_t nbytes);
ssize_t writen(int filedes, const void *buff, size_t nbytes);
ssize_t readline(int filedes, void *buff, size_t maxlen);
#include "unp.h"
ssize_t readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr=vptr;
nleft=n;
while(nleft>0)
{
if((nread=read(fd, ptr, nleft))<0)
{
if(errno==EINTR)
nread=0;
else
return -1;
}
else if(nread==0)
{
break;
}
nleft-=nread;
ptr+=nread;
}
return n-nleft;
}
readn function: Read n bytes from a descriptor
#include "unp.h"
ssize_t writen(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr=vptr;
nleft=n;
while(nleft>0)
{
if((nwritten=write(fd, ptr, nleft))<0)
{
if(nwritten<0&&errno==EINTR)
nwritten=0;
else
return -1;
}
nleft-=nwritten;
ptr+=nwritten;
}
return n;
}
writen function: Write n bytes to a descriptor
#include "unp.h"
ssize_t readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr=vptr;
for(n=1;n
readline function: Read a text line from a descriptor, one byte at a time
Our three functions look for the error EINTR (the system call was interrupted by a caught signal, which we will discuss in more detail in Section 5.9(See 8.3.9)) and continue reading or writing if the error occurs. We handle the error here, instead of forcing the caller to call readn or writen again, since the purpose of these three functions is to prevent the caller from having to handle a short count.