To go along with the multithreaded psychiatrist server, this section develops a multithreaded client named gab4.pl (Figure 11.3). It is similar to the byte stream-oriented forking client gab3.pl in Chapter 10 (Figure 10.4); but instead of forking a child process to read from the remote server, the read loop is done inside a thread running the do_read() subroutine. Figure 11.3. Threaded concurrent client The other major difference between this client and the previous version is the termination process. In both clients , when do_write() detects that standard input has been closed, the subroutine closes the transmission half of the socket by calling shutdown(1) . This sends an end of file to the server, causing it to close its side of the socket, and this event propagates back to the do_read() thread. So far so good, but what happens when the server is the one to initiate the disconnection? The do_read() thread detects the end-of-file condition and exits. However, the do_write() loop running in the main thread is usually blocked waiting for data from standard input and will not be notified of anything untoward until it tries to write a line of text to the socket and triggers a PIPE signal. In the forking client, we finessed this by having the CHLD handler call exit() . In the threading example, there is no CHLD signal to catch, and so the easiest course of action is just to have the host_to_user() thread call exit() . |