7.2 Java TCP Client Applications


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, which 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:

Finger.java

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
/** TCP finger client - by Derek Molloy ee402.eeng.dcu.ie
Usage: Finger username@host.com
*/

package ee402;

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

public class Finger
{
        
    public static void main (String args[]) {
      // Check command line arguments
      if (args.length != 1) {
           System.err.println ("Invalid number of parameters:");
             System.err.println ("Usage: Finger username@host");
             System.exit(1);
      }
      // Check for existence of @ in argument
      else if (args[0].indexOf("@") == -1) {
        System.err.println ("Invalid parameter : syntax user@host");
        System.exit(1);
      }
      // Split command line argument at the @ character
      String username = args[0].substring(0, args[0].indexOf("@") );
      String hostname = args[0].substring(args[0].indexOf("@") +1, args[0].length());
      
      try {
          System.out.println ("Connecting to " + hostname);

          // Create a connection to server
          Socket s = new Socket(hostname, 79);

          // Create input and output streams to socket
          PrintStream out = new PrintStream( s.getOutputStream()) ;
         
          BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));

          // Write username to socket output
          out.println(username);

          // Read response from socket
          String line = in.readLine();

          while (line != null) {
               System.out.println ( line );
               // Read next line
               line = in.readLine();
          }
          // Terminate connection
          s.close();
       }
       catch (SocketException e) {
          System.err.println ("Socket error : " + e);
       }
       catch (UnknownHostException e) {
          System.err.println ("Invalid host!");
       }
       catch (IOException e) {
          System.err.println ("I/O error : " + e);
       }
   }
}

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 7.3, “Finger Client Example”)

Figure 7.3. Finger Client Example

Finger Client Example

I have run the finger application three times in Figure 7.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 currently logged on, and the locations where they are logged on from. Note: Khumbu may not accept connections from clients outside my subnet for security reasons. So the process that occurs to get the output as in Figure 7.3, “Finger Client Example” is summarized in Figure 7.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 standardOutputStream 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.

Figure 7.4 Executing the Finger Client Application (Executed in 2013)


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 7.5. 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 web server and receives the HTML response.


123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
package ee402;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

@SuppressWarnings("serial")
public class BasicWebBrowser extends Frame implements ActionListener, WindowListener {

    private TextField hostname, page;
    private TextArea returnPage;
    
    public BasicWebBrowser() {
        super("Basic Web Browser Application");
        this.addWindowListener(this);
        
        Panel north = new Panel();
        north.setLayout(new FlowLayout());
        hostname = new TextField("www.eeng.dcu.ie",30);
        north.add(new Label("Site:"));
        north.add(hostname);
        page = new TextField("index.html", 30);
        north.add(new Label("Page:"));
        north.add(page);
        this.add(north, BorderLayout.NORTH);
        
        returnPage = new TextArea(10,40);
        this.add(returnPage, BorderLayout.CENTER);
   
        Button go = new Button("Load");
        go.addActionListener(this);
        this.add(go, BorderLayout.SOUTH);
        this.setSize(600,350);
        this.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        Socket httpSocket = null;
        DataOutputStream os = null; //output stream
        DataInputStream is = null; //input stream
        BufferedReader br = null;          //buffered reader for correct reading
        
        try {
            httpSocket = new Socket(this.hostname.getText(), 80); //HTTP port 80
            os = new DataOutputStream(httpSocket.getOutputStream());
            is = new DataInputStream(httpSocket.getInputStream());
            br = new BufferedReader(new InputStreamReader(is));
        } catch (UnknownHostException ex) {
            System.err.println("Don't know host: " + this.hostname.getText());
        } catch (IOException ex) {
            System.err.println("No I/O for the connection to: " + this.hostname.getText());
        }

        if (httpSocket != null && os != null && is != null) {
           try
           {
               this.returnPage.append("Sending Request\n");
               String theRequest = new String("GET /" + this.page.getText() + "\n\n");
               returnPage.append(theRequest);
                  os.writeBytes(theRequest);
                
                this.returnPage.append("Request Sent\n");
                // keep reading from/to the socket till we receive "Ok"
                // from HTTP server. Once received then break.

                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    this.returnPage.append(responseLine);
                    if (responseLine.indexOf("Ok") != -1) {
                      break;
                    }
                }
                this.returnPage.append("End of Response\n");
                os.close();
                is.close();
                httpSocket.close();
           }
           catch (UnknownHostException ex) {
                   System.err.println("Trying to connect to unknown host: " + ex);
           }
           catch (IOException ex) {
                   System.err.println("IOException: " + ex);
           }
        }
    }

    public static void main(String[] args) {
        new BasicWebBrowser();
    }

    public void windowActivated(WindowEvent arg0) {}
    public void windowClosed(WindowEvent arg0) {}
    public void windowClosing(WindowEvent arg0) {
                System.exit(0);
    }
    public void windowDeactivated(WindowEvent arg0) {}
    public void windowDeiconified(WindowEvent arg0) {}
    public void windowIconified(WindowEvent arg0) {}
    public void windowOpened(WindowEvent arg0) {}
}


These notes are copyright Dr. Derek Molloy, School of Electronic Engineering, Dublin City University, Ireland 2013-present. Please contact him directly before reproducing any of the content in any way.
Comments