Java TCP Client Applications

Introduction

Java removes much of the complexity of writing Network aware applications, by providing a Socket class (java.net.Socket). The socket is the software abstraction, used to represent the terminals of a connection between two machines. The basic concept is that you have two sockets on two machines and you create a connection between these sockets, that you use to transfer data. We don't care how the data gets from one socket to another, even though it might have to traverse many network hardware types (hence the abstraction).

We are going to write a finger client to demonstrate how TCP works in Java.

The Finger Client

Finger is a standard service that allows a remote machine to query a server and ask it for information on a particular user, or on the users that are logged on. Most UNIX systems support finger, however on many server systems it is disabled, as it provides a little bit too much information for potential 'hackers'.

The host server is usually located at port 79, where a request is usually made up of a username followed by the '\n' character. The server sends any information back to the client and then terminates the connection.

Here is the source for Finger.java that connects to any finger server and receives the output:

 1 
 2 
 3 // TCP finger client - Derek Molloy...
 4 // Usage: Finger username@host.com
 5 
 6   import java.io.*;
 7   import java.net.*;
 8 
 9   public class Finger
10   {
11     public static void main ( String args[] )
12     {
13       // Check command line paramaters
14 
15       if (args.length != 1)
16       {
17         System.err.println ("Invalid number of paramaters:");
18         System.err.println ("Usage: Finger username@host");
19         System.exit(1);
20       }
21       // Check for existence of @ in paramater
22       else if (args[0].indexOf("@") == -1)  
23       {
24         System.err.println ("Invalid paramater : syntax user@host");
25         System.exit(1);
26       }
27 
28       // Split command line paramater at the @ character
29       String username = args[0].substring(0, args[0].indexOf("@") );
30       String hostname = args[0].substring(args[0].indexOf("@") +1, 
31                                  args[0].length());
32       try
33       {
34           System.out.println ("Connecting to " + hostname);
35 
36           // Create a connection to server
37           Socket s = new Socket(hostname, 79);
38 
39           // Create input and output streams to socket
40           PrintStream out = new PrintStream( s.getOutputStream()) ;
41          
42           BufferedReader in = new BufferedReader(
43 			new InputStreamReader( s.getInputStream()));
44 
45 
46           // Write username to socket output
47           out.println( username );
48 
49           // Read response from socket
50           String line = in.readLine();
51 
52           while (line != null)
53           {
54                System.out.println ( line );
55 
56                // Read next line
57                line = in.readLine();
58           }
59 
60           // Terminate connection
61           s.close();                        
62        }
63        catch (SocketException e )
64        {
65           System.err.println ("Socket error : " + e);
66        }
67        catch (UnknownHostException e )
68        {
69           System.err.println ("Invalid host!");
70        }
71        catch (IOException e )
72        {
73           System.err.println ("I/O error : " + e);
74        }
75      }
76   }
77 
78 

When the Finger application is run it expects the name of a user@host, either specified by the full Internet name, or the name of a machine on the same network segment. If you forget to provide the parameters, it prompts you for the correct parameters (See Figure 10.3, “Finger Client Example”)

Figure 10.3. Finger Client Example

Finger Client Example

I have run the finger application three times in Figure 10.3, “Finger Client Example”. The first time I omitted the parameter by typing java Finger and I was then prompted for the correct parameter. In the second case I typed java Finger molloyd@khumbu.eeng.dcu.ie and this searches for the username molloyd at the hostname khumbu.eeng.dcu.ie (a Unix server in the school with a finger server installed) and this returns details about this user. In the third case I omitted the username and just typed java Finger @khumbu.eeng.dcu.ie. The finger server is designed in this case to return a list of users that are currentl logged on, and the locations where they are logged on from. Note: Khumbu may not accept connections from clients outside of DCU for security reasons. So the process that occurs to get the output as in Figure 10.3, “Finger Client Example” is sumarised in Figure 10.4, “Finger Client/Server Process”

Figure 10.4. Finger Client/Server Process

Finger Client/Server Process

The Finger application consists of three main steps:

  • Import the Network API and I/O packages. Add the main() method that is responsible for all the coding. Receive the parameters from the command line args[] and extract the username and hostname from a String object of the form "user@some.host.com".

  • Connect to the server that runs on port 79 (The standard finger protocol port). Try to catch any exceptions that may occur, such as SocketException if the socket does not establish correctly, UnknownHostException if the host is invalid and otherwise if an error occurs during reading/writing a general IOException may occur.

  • After establishing the connection. Write the output to the server and then read in the input stream. For the output stream in this case I use a PrintStream that provides convenient functionality over and above the standard OutputStream such as the println() method that we use. To create the PrintStream object we pass the standard OutputStream object to its constructor. For reading the reply from the server we use the BufferedReader class. Before the current JDK we would have used the InputStreamReader but there was an error in the way that the readLine() was used, and so we must use the BufferedReader class. This class provides the extra functionality on top of the standard InputStream such as the readLine() that we need for this application.

The Basic Web Browser

Another example of a client application is a basic web browser. This application allows you to connect to any web server (depending on your proxy) and request a web page. The result is returned in HTML and displayed in the text area as shown below

Figure 10.5. The Basic Web Browser Application

The Basic Web Browser Application

This application connects to a web site on port 80 and sends the string GET /index.html \n\n where index.html is the page entered in the visual interface. It then reads the response from the server and outputs to the text area.

Here is the source for BasicWebBrowser.java that connects to any finger server and receives the output:

 1 
 2 import java.awt.*;
 3 import java.awt.event.*;
 4 import java.io.*;
 5 import java.net.*;
 6 
 7 /**
 8  * @author Derek Molloy
 9  */
10 
11 public class BasicWebBrowser extends Frame implements ActionListener {
12 
13     private TextField hostname, page;
14     private TextArea returnPage;
15     
16     public BasicWebBrowser()
17     {
18         super("Basic Web Browser Application");
19         
20         this.setLayout(new FlowLayout());
21         
22         hostname = new TextField("www.eeng.dcu.ie",40);
23         this.add(new Label("SITE"));
24         this.add(hostname);
25         page = new TextField("index.html", 40);
26         this.add(new Label("Page:"));
27         this.add(page);
28         
29         returnPage = new TextArea(10,40);
30         this.add(returnPage);
31         
32         Button go = new Button("GO");
33         go.addActionListener(this);
34         this.add(go);
35         this.setSize(400,350);
36         this.setVisible(true);    
37     }
38 
39     public void actionPerformed(ActionEvent e) {
40             
41         Socket httpSocket = null;  
42         DataOutputStream os = null;   //output stream
43         DataInputStream is = null;    //input stream
44         BufferedReader br = null;     // buffered reader for correct reading
45         
46 
47         try {
48             httpSocket = new Socket(this.hostname.getText(), 80);   //HTTP port 80
49             os = new DataOutputStream(httpSocket.getOutputStream());
50             is = new DataInputStream(httpSocket.getInputStream());
51             br = new BufferedReader(new InputStreamReader(is));
52         } catch (UnknownHostException ex) {
53             System.err.println("Don't know host: " + this.hostname.getText());
54         } catch (IOException ex) {
55             System.err.println("No I/O for the connection to: " + this.hostname.getText());
56         }
57 
58         if (httpSocket != null && os != null && is != null)
59         {
60            try
61            {
62                this.returnPage.append("Sending Request\n");
63                String theRequest = new String("GET /" + this.page.getText() + "\n\n");
64                returnPage.append(theRequest);
65                   os.writeBytes(theRequest);
66                 
67                 this.returnPage.append("Request Sent\n");
68                 // keep reading from/to the socket till we receive "Ok"
69                 // from HTTP server. Once received then break.
70 
71                 String responseLine;
72                 while ((responseLine = br.readLine()) != null) {
73                     this.returnPage.append(responseLine);
74                     if (responseLine.indexOf("Ok") != -1) {
75                       break;
76                     }
77                 }
78                 this.returnPage.append("End of Response\n");
79                 os.close();
80                 is.close();
81                 httpSocket.close();   
82            }
83            catch (UnknownHostException ex) {
84                    System.err.println("Trying to connect to unknown host: " + ex);
85            }
86            catch (IOException ex) {
87                    System.err.println("IOException:  " + ex);
88            }
89         }
90     }
91 
92     public static void main(String args[]) {
93         new BasicWebBrowser();
94     }
95 }
96