> ### Solution for
> Programming Exercise 10.5

> THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

> Exercise 10.5: Write a client program for the server from Exercise 10.4. Design a user interface that will let the user do at least two things: Get a list of files that are available on the server and display the list on standard output. Get a copy of a specified file from the server and save it to a local file (on the computer where the client is running).

> Discussion

> One possible user interface would be to use a menu, as was done in the solution to Exercise 10.3. For variety, however, I decided on an interface based entirely on the command line. The first command line argument must be the name or IP address of the computer where a copy of the `FileServer` program from Exercise 10.4 is running. If that is the only command-line argument, then the client will contact the server and send an "index" command to the server. The server responds with a list of file names. The client reads these names and displays them on the screen. The program then ends. (If you want to give another command, you have to run the client program again with a new command line.)

> If there are two command-line arguments, then the second argument must be the name of a file on the server. The client contacts the server and sends a "get" command. The server responds with a one-line message, either "error" or "ok". The client reads this message. If the message is "error", indicating that the requested file can't be sent, then the client just displays an error message to the user. If the message is "ok", then the server also sends the contents of the file. The client tries to create a local file of the same name. It reads the data from the server and saves it to that file. However, for safety, the client will not create a new file if a local file of the same name already exists. This is considered to be an error. (There was no particular reason to do things this way -- I just wanted to make my interface a bit fancier.)

> Finally, I wanted to make it possible to save a downloaded file in a local file with a different name. For this, three command line arguments are used. The first is the server, the second is the name of the file on the server, and the third is the name of the local file where the downloaded file is to be saved. In this case, the program is willing to overwrite an existing file of the same name, so the command must be used with some care.

> If the server program is running on the same computer as the client (for demonstration purposes), the the following command lines can be used to run the client:

>           java FileClient  172.0.0.1
>           java FileClient  172.0.0.1  datafile.txt
>           java FileClient  172.0.0.1  datafile.txt  mycopy.dat
>           java FileClient  172.0.0.1  datafile.txt  datafile.txt

> The first command shows a list of files that are available on the server. The other three all try to get a file named "datafile.txt" from the server.

> The actual programming of the client is fairly straightforward. The example program DateClient.java provides a model for opening a connection to the server and for sending and receiving data over the connection. You should be able to follow the solution, given below.

> By the way, once you understand how the `FileClient` and `FileServer` examples work, it's not a big conceptual leap to understanding how the World Wide Web works. A Web server program is just a greatly souped-up version of the `FileServer` program. It has access to a collection of files. It receives and responds to requests for those files from client programs. To get a file, the client program -- a Web browser -- needs to know the computer on which the server is running and the name of the file. This information is encoded in the url address of a Web page -- just like it's given on the command line of the `FileClient` program. A Web page, of course, can contain links to other Web pages. The link includes a url with the necessary information for finding the page. To get the page, the Web browser just goes through the same process of contacting the specified server and requesting the specified file. (One big complication is that not all the files on a Web server are text files, so the client needs some way of knowing what type of data is stored in the file, and it needs to know how to handle data of that type.)

> The Solution

>        /*
>            This program is a client for the FileServer server.  The
>            server has a list of available text files that can be
>            downloaded by the client.  The client can also download
>            the list of files.  When the connection is opened, the
>            client sends one of two possible commands to the server:
>            "index" or "get <file-name>".  The server replies to
>            the first command by sending the list of available files.
>            It responds to the second with a one-line message,
>            either "ok" or "error".  If the message is "ok", it is
>            followed by the contents of the file with the specified
>            name.  The "error" message indicates that the specified
>            file does not exist on the server.  (The server can also
>            respond with the message "unknown command" if the command
>            it reads is not one of the two possible legal commands.)

>            The client program works with command-line arguments.
>            The first argument must be the name or IP address of the
>            computer where the server is running.  If that is the
>            only argument on the command line, then the client
>            gets the list of files from the server and displays
>            it on standard output.  If there are two parameters,
>            the second parameter is interpreted as the name of a
>            file to be downloaded.  A copy of the file is saved
>            as a local file of the same name, unless a file of
>            the same name already exists.  If there are three
>            arguments, the second is the name of the file to be
>            downloaded and the third is the name under which the
>            local copy of the file is to be saved.  This will
>            work even if a file of the same name already exists.

>            This program uses the non-standard class, TextReader.
>        */

>        import java.net.*;
>        import java.io.*;

>        public class FileClient {

>           static final int LISTENING_PORT = 3210;

>           public static void main(String[] args) {

>              String computer;      // Name or IP address of server.
>              Socket connection;    // A socket for communicating with
>                                    //                that computer.
>              PrintWriter outgoing; // Stream for sending a command
>                                    //                to the server.
>              TextReader incoming;  // Stream for reading data from
>                                    //                the connection.
>              String command;       // Command to send to the server.

>              /* Check that the number of command-line arguments is legal.
>                 If not, print a usage message and end. */

>              if (args.length == 0 || args.length > 3) {
>                 System.out.println("Usage:  java FileClient <server>");
>                 System.out.println("    or  java FileClient <server> <file>");
>                 System.out.println(
>                       "    or  java FileClient <server> <file> <local-file>");
>                 return;
>              }

>              /* Get the server name and the message to send to the server. */

>              computer = args[0];

>              if (args.length == 1)
>                 command = "index";
>              else
>                 command = "get " + args[1];

>              /* Make the connection and open streams for communication.
>                 Send the command to the server.  If something fails
>                 during this process, print an error message and end. */

>              try {
>                 connection = new Socket( computer, LISTENING_PORT );
>                 incoming = new TextReader( connection.getInputStream() );
>                 outgoing = new PrintWriter( connection.getOutputStream() );
>                 outgoing.println(command);
>                 outgoing.flush();
>              }
>              catch (Exception e) {
>                 System.out.println(
>                      "Can't make connection to server at \"" + args[0] + "\".");
>                 System.out.println("Error:  " + e);
>                 return;
>              }

>              /* Read and process the server's response to the command. */

>              try {
>                 if (args.length == 1) {
>                       // The command was "index".  Read and display lines
>                       // from the server until the end-of-stream is reached.
>                    System.out.println("File list from server:");
>                    while (incoming.eof() == false) {
>                       String line = incoming.getln();
>                       System.out.println("   " + line);
>                    }
>                 }
>                 else {
>                       // The command was "get <file-name>".  Read the server's
>                       // response message.  If the message is "ok", get the file.
>                    String message = incoming.getln();
>                    if (! message.equals("ok")) {
>                       System.out.println("File not found on server.");
>                       return;
>                    }
>                    PrintWriter fileOut;  // For writing the received data to a file.
>                    if (args.length == 3) {
>                          // Use the third parameter as a file name.
>                        fileOut = new PrintWriter( new FileWriter(args[2]) );
>                    }
>                    else {
>                          // Use the second parameter as a file name,
>                          // but don't replace an existing file.
>                        File file = new File(args[1]);
>                        if (file.exists()) {
>                           System.out.println("A file with that name already exists.");
>                           System.out.println("To replace it, use the three-argument");
>                           System.out.println("version of the command.");
>                           return;
>                        }
>                        fileOut = new PrintWriter( new FileWriter(args[1]) );
>                    }
>                    while (incoming.peek() != '\0') {
>                           // Copy lines from incoming to the file until
>                           // the end of the incoming stream is encountered.
>                        String line = incoming.getln();
>                        fileOut.println(line);
>                    }
>                    if (fileOut.checkError()) {
>                       System.out.println("Some error occurred while writing the file.");
>                       System.out.println("Output file might be empty or incomplete.");
>                    }
>                 }
>              }
>              catch (Exception e) {
>                 System.out.println("Sorry, an error occurred while reading data from the server.");
>                 System.out.println("Error: " + e);
>              }

>           }  // end main()

>        } //end class FileClient

> [ Exercises | Chapter Index | Main Index ]