Search code examples
csocketsnetworkingioc-standard-library

Why the restrictions on C standard I/O streams that interact with sockets?


In book CSAPP section 10.9, it says that there are two restrictions on standard I/O streams that interact badly with restrictions on sockets.

Restriction 1: Input functions following output functions. An input function cannot follow an output function without an intervening call to fflush, fseek, fsetpos, or rewind. The fflush function empties the buffer associated with a stream. The latter three functions use the Unix I/O lseek function to reset the current file position.

Restriction 2: Output functions following input functions. An output function cannot follow an input function without an intervening call to fseek, fsetpos, or rewind, unless the input function encounters an end-of-file.

But I cannot figure out why the restrictions imposed. So, my question is: what factors result to the two restrictions?

It also says that "It is illegal to use the lseek function on a socket.", but how is it possible fseek, fsetpos and rewind use lseek to reset the current file position if it is true?

There is a similar question here, but my question different from this one.


Solution

  • The stdio functions are for buffered file input and output. A socket is not a file, but a socket. It doesn't even have a file position, and the buffer requirements are quite distinct from ordinary files - sockets can have independent input and output buffers, stdio file I/O cannot!

    The problem is that the file input and file output share the same file position, and the operating system might have (and indeed will have on Unix) a distinct file position from what the file position due to the buffering in C would be.

    Hence, from C99 rationale

    A change of input/output direction on an update file is only allowed following a successful fsetpos, fseek, rewind, or fflush operation, since these are precisely the functions which assure that the I/O buffer has been flushed.

    Note that all this applies to only files opened with + - with files opened in any other standard modes, it is not possible to mix input and output.

    Since it is required by the C standard that when switching from input to output on FILE * one of the functions fsetpos, rewind or fseek, which essentially invoke lseek must be successful (mind you, calling fflush causes the buffered output to be written, and certainly not discarding the buffered input) before an output function is attempted... yet a socket is not seekable and lseek would therefore always fail - it means that you cannot use a FILE * that has been opened for both reading and writing wrapping the socket for actually both reading from and writing to the socket.


    It is possible to use fdopen to open a FILE * with stream sockets if you really need to: just open two files - one "rb" for input and another with "wb" for output.