Programming Clients Using Sockets

A socket is an abstract input-output device. A socket may correspond to a display, a keyboard, a printer or a data communications line. A socket is used by a program to input or output a stream of data.

A client socket can:

A client socket is normally used as follows:

  1. A new socket is created, using the Java Socket constructor.
  2. The socket attempts to connect to a remote host.
  3. Once the connection has been established, the local machine and the remote machine send and receive data. The connection is full-duplex, meaning that the data can be sent in both directions simultaneously.
  4. When the transmission is complete, the connection is closed by one or both machines.

In Java, the class Socket provides a way of using TCP sockets. (There are other types of socket, including datagram sockets.) The constructor method:

When a socket is created, either the host name is supplied, or an InetAddress object.


Example - A Port Scanner Program

The following program attempts to connect to ports 1 to 256 of a specified host. It thus checks to see which of these ports are "open for business", as it were.

It works by first inputting a host name, then trying to create an InetAddress object. If this fails, the host is unknown and an error message is displayed. The program then tries to open ports 1 to 256 on the host. If a socket is created, there is assumed to be an open port and a message is displayed. If a socket cannot be opened on a port, an exception is raised and the port is simply ignored. It might be helpful to look at

Program Psuedocode

Input host name
Check that host exists
for port = 1 to 256 do
    Try to open socket to port
    if socket opens
        Display port number
    Close socket
endfor
// PortScanner.java
// Scans ports from numbers 1 through 256 and
// reports those which are active.

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

public class PortScanner
    extends Frame
    implements ActionListener
{
    private TextField hostInput;
    private TextArea report;
    private Button button, exit;


    public static void main(String [] args)
    {
        PortScanner lfp = new PortScanner();
        lfp.makeGUI();
        lfp.setSize(525, 280);
        lfp.setVisible(true);
    }


    public void makeGUI()
    {
        setLayout(new FlowLayout());

        button = new Button("Enter host name below and click here to " +
                            "display server ports found on that host:");
        add(button);

        hostInput = new TextField("cs.stmarys.ca", 40);
        add(hostInput);

        report = new TextArea("", 0, 0,
                              TextArea.SCROLLBARS_VERTICAL_ONLY);
        add(report);
        button.addActionListener(this);

        exit = new Button("Exit");
        add(exit);
        exit.addActionListener(this);

     }


     public void actionPerformed(ActionEvent event)
     {
        if (event.getSource() == exit)
            System.exit(0);

        report.setText("");
        String host = hostInput.getText();
        try
        {
            InetAddress theAddress = InetAddress.getByName(host);
            for (int i=0; i<256; i++)
            {
                try
                {
                    Socket socket = new Socket(host, i);
                    report.append("There is a server on port " +
                                  i + "\n");
                    socket.close();
                }
                catch (IOException e)
                {
                    // No server on that port ...
                    // report.append("Exception: Problem on port " +
                    //               i + ": " + e.toString());

                }
            }
        }
        catch (UnknownHostException e)
        {
            report.setText("Unknown host");
        }
    }
}


Details about sockets

When a socket is created and a connection established, the server host name and port are specified. But there is also implicitly a client host port number involved, and this is part of the information encapsulated in a socket. This is chosen by the system at run time from available unused ports. The local port number is embedded in the IP packet along with the local host's IP address, so that the server can send the reply back to the right place. This port number can be accessed using getLocalPort(), one of the Socket class object methods (see the reference summary).

A socket is closed when:

Once a socket has been used to connect to a host, the program should close it. This is just good housekeeping.

The methods getInputStream() and getOutputStream() of the class Socket create objects of the classes InputStream and OutputStream, respectively. These can then be used to do stream input and output. It is usually best to create stream objects, which provide better functionality.

Now the world is your oyster - you can write programs to open connections to any host on any port and engage in conversation according to one of the established protocols (or your own special protocol if you can write a server).


Example - The Daytime Protocol (RFC867)

As an example of writing a client, the protocol daytime enables a client to obtain the date and time from port 13 of a host, providing of course that the host is in fact providing that servie. The client merely opens the connection, and sends nothing. In response the server sends a line of text, giving the current date and time on the server. Once again, take a look at the

Program Pseudocode

Open a socket to port 13 on the desired computer
Open an input stream
Read the date and time from the stream
Display that date and time
Close the socket
// GetRemoteTime.java
// Retrieves the time from a "remote" server.

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

public class GetRemoteTime
    extends Frame
    implements ActionListener
{
    private TextField hostInput;
    private TextArea display;
    private Button button;
    private Button exit;

    public static void main(String [] args)
    {
        GetRemoteTime gr = new GetRemoteTime();
        gr.makeGUI();
        gr.setSize(550, 300);
        gr.setVisible(true);
    }

    public void makeGUI()
    {
        setLayout(new FlowLayout());

        hostInput = new TextField(50);
        add(hostInput);
        button = new Button("Get time from this host");
        add(button);
        display = new
            TextArea("", 0, 0, TextArea.SCROLLBARS_VERTICAL_ONLY);
        add(display);
        button.addActionListener(this);

        exit = new Button("Exit");
        add(exit);
        exit.addActionListener(this);
    }

    public void actionPerformed(ActionEvent event)
    {
        if (event.getSource() == exit)
            System.exit(0);

        String theTime;
        String host = hostInput.getText();

        try
        {
            Socket socket = new Socket(host, 13);
            BufferedReader input = new
                BufferedReader(new
                InputStreamReader(socket.getInputStream()));
            theTime = input.readLine();
            display.append("The time at " + host +
                           " is " + theTime + ". ");

            socket.close();
        }
        catch (UnknownHostException e)
        {
            display.setText("No such host. ");
        }
        catch (IOException io)
        {
            display.setText(io.toString());
        }
    }
}

When you run this program, try entering localhost as the host name, to connect back to your own machine.


Errors and Exceptions

Several things can go wrong when a socket is created and a connection sought or used:

A ConnectException means thatthe connection is refused by the remote host. This may be because the host is busy, or because there is no server on that port.

A NoRouteToHostException means thatthe connection has timed out.

Normally, when a program reads from a socket, the call on the read thread blocks (waits) until the data has been obtained. But if the remote host crashes, the program is left hanging. An alternative is to call setSoTimeout to set the maximum waiting time. When this time expires, an InterruptedException is thrown.


Inputting and Outputting with Sockets

A socket connection can be used in both directions at once.

For input, it is most convenient to create a BufferedReader as follows:

BufferedReader in = new
    BufferedReader(new
    InputStreamReader(socket.getInputStream()));

Thereafter, method readLine can be used to input a complete line as a string (minus the terminating character(s)):

String string = in.readLine();

The end of the stream is signalled by a string equal to the null object. Thus a common pattern for input is:

String string;
while((string = in.readLine()) != null)
{
    processLine();
}

For output to a stream, it is most convenient to create a PrintWriter object like

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

and thereafter use method println to output a line (the line terminator is automatically added):

out.println("string");

Closing a socket closes all of the associated streams.


So, Java provides a Socket class that allows us to connect machines over a network or the Internet:

Class name:

Socket

Import:

import java.net.*;


Summary of class Socket Info

Method

Description

Example

Constructors:

 

 

public Socket(String host, int port)

Creates a new Socket object corresponding to destination host and port

Socket socket = new Socket("www.shu.ac.uk", 80);

public Socket(InetAddress host, int port)

Creates a new Socket object corresponding to the InetAddress object and port

Socket socket = new Socket(inetAddress, 80);

Object Methods:

 

 

public InetAddress getInetAddress()

Returns the InetAddress object corresponding to the host that is, or will be, connected to.

InetAddress iNE = socket.getInetAddress();

public int getPort()

Returns the port number of the host to which the socket is, or will be, connected.

int port = socket.getPort();

public int getLocalPort()

Returns the local port number.

int port = socket.getLocalPort();

public InputStream getInputStream()

Returns an input stream that can be used by the program for input.

InputStream is = socket.getInputStream();

public OutputStream getOutputStream()

Returns an output stream that can be used by the program for output.

OutputStream os = socket.getOutputStream();

public synchronized void close()

Disconnects a socket. This also closes the streams associated with the socket.

socket.close();

public String toString()

Returns a string representation of a socket with remote host name, remote IP address, remote port, local port.

String details = socket.toString()

public synchronized void setSoTimeout(int ms)

Sets the time-out to the parameter value (in milliseconds).

socket. setSoTimeout(18000);

 

Summary of class BufferedReader Info

Method

Description

Example

public String readLine()

Inputs a string that is followed by a line terminator. The string does not include the terminator.

in.readLine();

 

Summary of class PrintWriter Info

Method

Description

Example

public void println(String)

Outputs a string, followed by a line terminator.

out.println("output line");


Questions: The goal of these questions is to help you clarify the understanding of ports and sockets:

  1. What are the differences between ports and sockets?
  2. For both sockets and ports, answer the following:

Exercises: The goal of these exercises is to help clarify the meaning of a "connection":

  1. Run the program PortScanner.java given above. This interrogates ports 1 to 256 of a particular host to see if it is possible to "connect" a socket to each of the ports. If so, a "connection" is established and this implies that a service is available on that port.
  2. Enhance the program so that it displays which ports it has looked at and which port it is looking at.
  3. Enhance the program so that it displays the local port number that has been used to connect to each remote port. (There will be a different local port number for every connection, chosen from those that are unused.)

Exercises: The goal of these exercises is to help you to understand sockets:

  1. Run the program GetRemoteTime.java given above.

  2. Write a program that uses the echo protocol to communicate with a server, one line at a time. Use separate text areas for the text sent to the server and the text sent from the server. Use a text field to specify the host name. Use a button to close the connection.
  3. Write a program that uses the finger protocol to get information about users of a host.

  4. Write a program that acts as a general-purpose telnet client. The program should provide: