The problem here is the buffering performed automatically by the standard I/O library on the server. There are three types of buffering performed by the standard I/O library:
1.Fully buffered means that I/O takes place only when the buffer is full, the process explicitly calls fflush, or the process terminates by calling exit. A common size for the standard I/O buffer is 8,192 bytes.
2.Line buffered means that I/O takes place when a newline is encountered, when the process calls fflush, or when the process terminates by calling exit.
3.Unbuffered means that I/O takes place each time a standard I/O output function is called.
Most Unix implementations of the standard I/O library use the following rules:
- Standard error is always unbuffered.
- Standard input and standard output are fully buffered, unless they refer to a terminal device, in which case, they are line buffered.
- All other streams are fully buffered unless they refer to a terminal device, in which case, they are line buffered.
Advanced Polling
Since none of these methods have been adopted by POSIX yet, and each implementation seems to be slightly different, code that uses these mechanisms should be considered nonportable. We’ll describe two mechanisms here; other available mechanisms are similar.
/dev/poll Interface
Solaris provides a special file called /dev/poll, which provides a more scalable way to poll large numbers of file descriptors. The problem with select and poll is that the file descriptors of interest must be passed in with each call. The poll device maintains state between calls so that a program can set up the list of descriptors to poll and then loop, waiting for events, without setting up the list again each time around the loop.
After opening /dev/poll, the polling program must initialize an array of pollfd structures (the same structure used by the poll function, but the revents field is unused in this case). The array is then passed to the kernel by calling write to write the structured directly to the /dev/poll device. The program then uses an ioctl call, DO_POLL, to block, waiting for events. The following structure is passed into the ioctl call:
struct dvpoll {
struct pollfd* dp_fds;
int dp_nfds;
int dp_timeout;
}
The field dp_fds points to a buffer that is used to hold an array of pollfd structures returned from the ioctl call. The field dp_nfds field specifies the size of the buffer. The ioctl call blocks until there are interesting events on any of the polled file descriptors, or until dp_timeout milliseconds have passed. Using a value of zero for dp_timeout will cause the ioctl to return immediately, which provides a nonblocking way to use this interface. Passing in -1 for the timeout indicates that no timeout is desired.
#include "unp.h"
#include <sys/devpoll.h>
void str_client(int sockfd)
{
int stdineof;
char buf[MAXLINE];
int n;
int wfd;
struct pollfd pollfd[2];
struct dvpoll dopoll;
int i;
int result;
wfd=Open("/dev/poll", O_RDWR,0);
pollfd[0].fd=fileno(fp);
pollfd[0].events=POLLIN;
pollfd[0].revents=0;
pollfd[1].fd=sockfd;
pollfd[1].events=POLLIN;
pollfd[1].revents=0;
Write(wfd, pollfd, sizeof(struct pollfd)*2);
stdineof=0;
for(;;)
{
if(dopoll.dp_fds[i].fd==sockfd)
{
if((n=Read(sockfd,buf,MAXLINE))==0)
{
if(stdineof==1)
return;
else
err_quit("str_client: server terminated prematurely");
}
Write(fileno(stdout), buf, n);
}
else
{
if((n=Read(fileno(fp),buf, MAXLINE))==0)
{
stdineof=1;
Shutdown(sockfd, SHUT_WR);
continue;
}
Writen(sockfd, buf, n);
}
}
}
str_cli function using /dev/poll