Recent Changes - Search:

Distributed Computing

This website demonstrates using wikis as teaching and learning tool.

The course instructor is also happy to share the teaching materials here with those who find it readable.

Tutorial - Building a Web Chat Program

Activity 1: Using telnet to access a web page

  • Open a command shell (i.e., DOS box), and execute the telnet program to connect to the host <www.ouhk.edu.hk> at port 80:
      C:\> telnet www.ouhk.edu.hk 80
  • When the telnet program starts, the screen is cleared. Type in the following two lines:
      C:\> GET /index.html HTTP/1.0
  • Press the [Enter] key twice consecutively. Observe the HTTP response from the web server.
Notes for your understanding :
HTTP communication can be divided into two separate parts, namely, HTTP requests and HTTP responses.
An HTTP request, which is made by a web client, contains information about a resource on the web server, and the action the client wishes the server to perform on the resource.
A web server fulfils an HTTP request by returning an HTTP response, which varies with the type of request and whether or not the request could be serviced.

Activity 2: Using a Java program to access a web page

Now, let’s look at the source code of a Java program that connects to a web server using the Socket’s API.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class WebClient {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter host name (e.g., www.ouhk.edu.hk): ");
        String host = scanner.nextLine();
        System.out.print("Enter page (e.g., /index.html): ");
        String page = scanner.nextLine();

        final String CRLF = "\r\n"; // newline
        final int PORT = 80; // default port for HTTP

        try {
            Socket socket = new Socket(host, PORT);
            OutputStream os = socket.getOutputStream();
            InputStream is = socket.getInputStream();

            PrintWriter writer = new PrintWriter(os);
            writer.print("GET " + page + " HTTP/1.0" + CRLF);
            writer.print(CRLF);
            writer.flush(); // flush any buffer

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null)
                System.out.println(line);

            socket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
Notes for your understanding :
The program first asks the user for the host name of the web server and the web page to be retrieved, and stores them in the host and page variables, respectively. Two constants, CRLF and PORT, are then defined for the end-of-line and default port number of HTTP.
The socket accessing code is enclosed in a try-catch block, due to the possible occurrence of IOException on network errors. In the try-catch block, a socket is created with the entered host name and the default port of 80. The output stream and input stream of the socket are obtained by calling the getOutputStream and getInputStream methods on the socket, respectively.
As HTTP is a text-based protocol, we wrap the binary OutputStream and InputStream into character-based streams for writing and reading lines of text. More specifically, a PrintWriter is created to wrap the OutputStream and two strings are written by using its print method. The two strings are a GET request line and an empty line. After that, the flush method is invoked on the PrintWriter to ensure that the output data in the buffer (of the Java implementation and/or the operating system) are actually sent down to the network.
With the HTTP request sent to the server, the program uses the BufferedReader class to obtain the input from the InputStream of the socket. The lines of input are read using the readLine method of BufferedReader in a while loop and printed to the screen, until readLine returns null which denotes the end of the input stream. At the end, we invoke the close method on the socket to free any resources used by it.
Your tasks : Compile and run the above program. Study the program and answer the following questions
  • Q1 - In the source code of the WebClient program, identify the four essential steps in establishing a TCP client.
  • Q2 - Why do we need to flush the output stream of the socket (via the wrapping PrintWriter) after writing the HTTP request? You may try to comment out or remove the line of writer.flush(); to observe the program’s behaviour if no flushing was performed.
  • Q3 - What is the use of invoking the close method on the socket at the end of the program?
  • Q4 - The program obtains the input and output streams from the socket. It closes the socket explicitly but not the two streams. Is it needed to close the streams explicitly? You may refer to the API documentation of the Socket class.

Activity 3: A GUI web client example

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Observable;
import java.util.Observer;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class WebClientGUI {

    /** Web client networking */
    static class WebClientAccess extends Observable {

        /** Requests the url */
        public void request(final String url, WebClientFrame clientFrame) {
            addObserver(clientFrame);
            Thread socketThread = new Thread() { // for long socket operations
                @Override
                public void run() {
                    connect(url);
                }
            };
            socketThread.start();
        }

        /** Formats url by removing protocol:// and appending / if necessary */
        private String parseUrl(String url) {
            String s = url;
            int pos = s.indexOf("://"); // if it has protocol://
            if (pos >= 0) // found
                s = s.substring(pos+3); // trim protocol://
            pos = s.indexOf('/'); // if it has /page.html part
            if (pos < 0) // not found
                s = s + "/"; // add default / as page
            return s;
        }

        private static final int PORT = 80; // default port for HTTP
        private static final String CRLF = "\r\n"; // newline

        /** Makes connection using host and page */
        private void connect(String url) {
            String s = parseUrl(url);
            String host = s.substring(0, s.indexOf('/'));
            String page = s.substring(s.indexOf('/'));
            try {
                Socket socket = new Socket(host, PORT);
                PrintWriter writer = new PrintWriter(socket.getOutputStream());
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));
                writer.print("GET " + page + " HTTP/1.0" + CRLF);
                writer.print(CRLF);
                writer.flush(); // flush any buffer

                String line;
                while ((line = reader.readLine()) != null) {
                    setChanged();
                    notifyObservers(line);
                }
                socket.close();
            } catch (IOException ex) {
                setChanged();
                notifyObservers("Exception: " + ex);
            }
            setChanged();
            notifyObservers(true);
        }
    }

    /** Web client UI */
    static class WebClientFrame extends JFrame implements Observer {

        private JTextField urlTextField;
        private JButton getButton;
        private JTextArea textArea;

        public WebClientFrame() {
            super("WebClientGUI");
            buildGUI();
        }

        /** Builds the user interface */
        private void buildGUI() {
            Box box = Box.createHorizontalBox();
            add(box, BorderLayout.NORTH);
            urlTextField = new JTextField();
            getButton = new JButton("Get");
            box.add(urlTextField);
            box.add(getButton);

            textArea = new JTextArea(30, 80);
            textArea.setEditable(false);
            textArea.setLineWrap(true);
            add(new JScrollPane(textArea), BorderLayout.CENTER);

            // Action for the urlTextField and the goButton
            ActionListener goListener = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    String inputURL = urlTextField.getText();
                    if (inputURL != null && inputURL.trim().length() > 0) {
                        setEnableInputUI(false);
                        textArea.setText("");
                        WebClientAccess webClient = new WebClientAccess();
                        webClient.request(inputURL.trim(), WebClientFrame.this);
                    }
                }
            };
            urlTextField.addActionListener(goListener);
            getButton.addActionListener(goListener);
        }

        /** Enables or disables the input url text field and get button */
        private void setEnableInputUI(boolean enable) {
            urlTextField.setEnabled(enable);
            getButton.setEnabled(enable);
        }

        /** Updates the UI depending on the Object argument */
        public void update(Observable o, Object arg) {
            final Object finalArg = arg;
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    if (finalArg instanceof Boolean) // enable or disable UI
                        setEnableInputUI((Boolean) finalArg);
                    else if (finalArg instanceof String) { // append string
                        textArea.append((String) finalArg);
                        textArea.append("\n");
                    }
                }
            });
        }
    }

    public static void main(String[] args) {
        JFrame frame = new WebClientFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);
    }
}
Your tasks : Compile, run and study the above program. It teaches you multi-thread programming and the observer design pattern.

Edit - History - Print - Recent Changes - Search
Page last modified on October 02, 2008, at 04:59 PM