Defining Buffer Operation
When you make use of the stdio(3) facilities, you generally make use of some buffering behind the scenes. Buffered writes, for example, reduce the frequency that the system function write(2) is called. This increases the overall system output efficiency. Likewise, read requests are also buffered.
For example, fgetc(3) will fetch one character from a buffer. Only when the input buffer is empty will it request more data to be read in using the read(2) system call. This, again, is done to
improve the I/O efficiency.
When the underlying file descriptor of a stream is a terminal device, the I/O under Linux will be line buffered. Files, on the other hand, are usually fully buffered (buffered in large blocks).
There are three basic modes of buffering to choose from using FILE streams under Linux. These are
- Fully buffered (or "block" buffered)
- Line buffered
Choosing "unbuffered" mode might be appropriate for some socket programs, although no efficiency from buffering can be gained this way. This does save you, however, from worrying about when to call fflush(3).
If your network application is experiencing hangs, the cause might be output buffering. Change the buffering on your output streams to "unbuffered mode" for testing. If the problem vanishes, then you need some calls to fflush(3) added to the appropriate places. Alternatively, you could reconsider the buffering mode being used by the application.
Line buffered mode is often useful when your socket interaction is text line based. Using line buffered mode means that you are never forced to call upon fflush(3) to force the last text line to be written to the socket.
If you choose to use the "fully" buffered mode, then you must apply fflush(3) at the point where you want a physical write to take place to the socket. Otherwise, your data might sit in an output buffer, while your application waits in vain for a response, because the output data was never sent. The function synopses of the buffer control functions are shown in Listing 10.3.
* Listing 10.3: Stream I/O Buffer Functions
int setbuf(FILE *stream,char *buf);
int setbuffer(FILE *stream, char *buf, size_t size);
int setlinebuf(FILE *stream);
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
The functions in Listing 10.3 permit the caller to change the buffering mode of the specified stream. The Linux documentation indicates that these functions might be called at any time to change the buffering characteristics of the stream. The non-setvbuf(3) calls are aliases to the function setvbuf(3), which performs the operation.
If your code must be portable to other UNIX platforms, then you must only call the buffer adjustment functions before I/O calls have been made on the streams affected. The arguments, by argument name, are described as follows:
- Argument stream is the FILE pointer of the stream that is to be affected.
- Argument buf is the pointer to the buffer being supplied. This pointer can be NULL. If a buffer is required, and NULL is supplied, then an internal buffer is allocated instead.
- Argument size is the size in bytes of the buffer provided (by argument buf), or the size of the internal buffer to be allocated.
- Argument mode is the buffering mode to be used.
A suggested buffer size is defined by the include file stdio.h as the macro BUFSIZ. Table 10.1 shows the list of mode values that can be supplied to setvbuf(3).
Table 10.1: The Mode Values for setvbuf(3)
Input and/or output on the stream will be fully buffered.
Input and/or output will be line buffered.
Input and/or output will not be buffered at all.
As an example of how to use the function to change the socket stream tx to use line buffered mode, you could code the following function call after the fdopen(3) call:
setlinebuf(tx); /* Line Buffered Mode */
Alternatively, you could accomplish the same thing by using the setvbuf(3) function directly:
In this example, you allow the software to allocate its own internal buffer of BUFSIZ bytes. The buffering mode for the stream, however, is set to line buffered mode, due to the use of the macro _IOLBF in the function call.