A Multithreaded Psychiatrist Server


 
Network Programming with Perl
By Lincoln  D.  Stein
Slots : 1
Table of Contents
Chapter  11.   Multithreaded Applications

    Content

A Multithreaded Psychiatrist Server

Despite the long introduction to threads, an actual multithreaded server is quite short. Here we develop a multithreaded version of the psychiatrist server (Figure 11.1).

Figure 11.1. Multithreaded psychiatrist server

graphics/11fig01.gif

Lines 1 “5: Load modules We begin by loading IO::Socket and the Thread module. We also bring in a specialized version of Chatbot::Eliza in which the command_interface() method has been rewritten to work well in a multithreaded environment (Figure 11.2).

Figure 11.2. The Chatbot::Eliza::Server class

graphics/11fig02.gif

Lines 6 “12: Create listening socket As in the previous examples, we create a new listening socket with IO::Socket::INET->new() . If a listening socket can't be created, we die with the error message IO::Socket leaves in $ .

Lines 12 “15: Accept loop We now enter the server's main loop. Each time through the loop we call accept() , yielding a new socket connected to the incoming client. We launch a new thread to handle the connection by calling Thread->new() with a reference to the interact() subroutine and the connected socket as its single argument. We then go back to waiting on accept() .

Notice that there is no need to close the listen or accept socket, as we did in the forking server examples. This is because duplicate socket handles are never created.

Lines 16 “31: The interact() subroutine This subroutine handles the conversation with the user and runs in a separate thread. Since the main server never checks the return value of the connection threads it launches, there's no need to keep this status information; so we begin by detaching ourselves from the main thread.

We next create a new Chatbot::Eliza::Server object and invoke its command_interface() method. Unlike the previous examples, this subclass does not read and write to STDIN and STDOUT but to a pair of filehandles passed in the argument list. The first argument is a filehandle to read the user's remarks from, and the second is a filehandle to write the psychotherapist 's responses to. In this case, the two filehandles are both the connected socket. We let command_interface() do its thing, then close the socket.The thread terminates when the subroutine ends.

The Chatbot::Eliza::Server Class

The reason for subclassing Chatbot::Eliza is simple. The class's command_interface() method is hardwired to use STDIN and STDOUT . In the forking server examples, we were able to trick Chatbot::Eliza into reading and writing to the connected socket by reopening standard input and output on the socket filehandle. This worked because each child process had its own copies of STDIN and STDOUT and we could alter them without affecting other children that might be running concurrently. In the multithreaded example, however, this trick won't work because there is only a single copy of the STDIN and STDOUT filehandles shared among all the threads. Therefore, command_interface() must be rewritten to read and write to filehandles that are passed to it at runtime.

Figure 11.2 shows the code necessary to achieve this. The module inherits from Chatbot::Eliza via the @ISA array. It then redefines the command_interface() method.

To create command_interface() , I simply duplicated the original Chatbot::Eliza code and added the new filehandle argument to all print and read statements (I also removed some extraneous debugging code). To remain compatible with the original version of the module, the filehandles used for reading and writing will default to STDIN and STDOUT , if not otherwise specified.


   
Top


Network Programming with Perl
Network Programming with Perl
ISBN: 0201615711
EAN: 2147483647
Year: 2000
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net