6.4 Pipes and the Client-Server ModelThe client-server model is a standard pattern for process interaction. One process, designated the client, requests a service from another process, called the server. The chapters in Part 4 of the book develop and analyze applications that are based on the client-server model with network communication. This section introduces client-server applications that use named pipes as the communication vehicle. We look at two types of client-server communicationsimple-request and request-reply. In simple-request, the client sends information to the server in a one-way transmission; in request-reply the client sends a request and the server sends a reply.Programs 6.7 and 6.8 illustrate how the simple-request protocol can be useful in logging. The client writes logging information to a named pipe rather than to standard error. A server reads from the named pipe and writes to a file. At first glance, the use of the named pipe appears to have added an extra step with no benefit. However, pipes and FIFOs have a very important propertywrites of no more than PIPE_BUF bytes are guaranteed to be atomic. That is, the information is written as a unit with no intervening bytes from other writes. In contrast, an fprintf is not atomic, so pieces of the messages from multiple clients might be interspersed.The server of Program 6.7 creates the pipe if it does not already exist. The server opens the pipe for both reading and writing, even though it will not write to the pipe. When an attempt is made to open a pipe for reading, open blocks until another process opens the pipe for writing. Because the server opens the pipe for reading and writing, open does not block. The server uses copyfile to read from the pipe and to write to standard output. To write to a file, just redirect standard output when the server is started. Since the server has the pipe open for writing as well as reading, copyfile will never detect an end-of-file. This technique allows the server to keep running even when no clients are currently writing to the pipe. Barring errors, the server runs forever. Program 6.7 pipeserver.cThe program reads what is written to a named pipe and writes it to standard output.
The client in Program 6.8 writes a single line to the pipe. The line contains the process ID of the client and the current time. Multiple copies of Program 6.8 can run concurrently. Because of the atomic nature of writes to the pipe, pieces of the messages from different clients are not interleaved. Program 6.8 pipeclient.cThe client writes an informative message to a named pipe.
Exercise 6.11How would you start Program 6.7 so that it uses the pipe mypipe and the log file it creates is called mylog? When will the program terminate?Answer:
The program does not terminate unless it is killed. You can kill it by typing Ctrl-C at the keyboard. No client error can cause the server to terminate. Exercise 6.12Start the pipeserver of Section 8.4 explains how to respond to these types of signals.Section 6.10 explores an alternative strategy in which the server creates a separate named pipe for each distinct client. Now each pipe only has a single reader, eliminating the two problems described above. Program 6.9 seqserverbad.cA sequence server reads a character from the request pipe and transmits a sequence number to the sequence pipe. (See text for a discussion.)
Program 6.10 seqclientbad.cThe client writes a request to a request pipe and reads the sequence number from the sequence pipe. This client can cause the server to exit.
The situation with nonatomic reads from pipes can actually be worse than described here. We have assumed that a read becomes nonatomic as follows.
Under these circumstances the first client detects an error, and the server shuts down. The second client may or may not know an error occurred.However, another scenario is technically possible, although it is very unlikely. Suppose the server writes two 4-byte integer sequence numbers and the bytes in the pipe are abcdefgh. The POSIX standard does not exclude the possibility that the first client will read the bytes abgh and the second one will read the bytes cdef. In this case, the sequence numbers are incorrect and the error is not detected at all. Exercise 6.13Try running one copy of Program 6.9 (seqserverbad) and two copies of Program 6.10 (seqclientbad). What happens?Answer:This should work correctly. The two copies of seqclientbad should get disjoint sets of sequence numbers. Exercise 6.14Try running two copies of Program 6.9 (seqserverbad) and one copy of Program 6.10 (seqclientbad). What happens?Answer:Either server can respond to a request for a sequence number. It is possible that the client will get the same sequence number twice. Exercise 6.15Change the seqclientbad to have a SLEEP_MAX of 0 and a REPEAT_MAX of 1,000,000. Comment out the last fprintf line. Run two copies of the client with one copy of the server. What happens?Answer:It is possible, but unlikely, that the server will terminate because one of the clients received an incorrect number of bytes when requesting the sequence number. |