INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM

ICS201, SECTIONS 52  (002 Semester)

INTRODUCTION TO COMPUTER SCIENCE

LAB  # 11: Networking

 

Instructor: Bashir M. Ghandi

 


1. Objectives:

 

2.  Internet Addresses

Every computer on the Internet is identified by a unique, four-byte IP address. This is typically written in dotted quad format like 199.1.32.90 where each byte is an unsigned value between 0 and 255.

 

Since humans have trouble remembering numbers like this, these addresses are mapped to names like "icswww.ccse.kfupm.edu.sa.com" called host names.

 

The class java.net.InetAddress is used to represent such an address in Java.  This class contains methods to convert numeric addresses to host names and host names to numeric addresses.   Some of its methods are shown below:

public static InetAddress getByName(String host)
throws UnknownHostException

used to instantiate an object of the class.  The class has no constructor.

public static InetAddress getLocalHost() throws
UnknownHostException

used to get the address of the local computer.

public String getHostName()

 

returns the name of the computer represented  by the current InetAddress object

public String getHostAddress()

 

returns the IP address of the computer represented  by the current InetAddress object

 

Example 1:  The following example returns the IP address and name of the computer on which the program is executed.  Execute the program and take note of the IP and name of your computer.

import java.net.*;

 

public class MyInternetAddress {

   public static void main(String args[]) {

      try {

         InetAddress localaddr = InetAddress.getLocalHost();

         System.out.println ("Local IP Address : " + localaddr.getHostAddress());

         System.out.println ("Local hostname   : " + localaddr.getHostName());

      }

      catch (UnknownHostException e) {

         System.err.println ("Can't detect localhost : " + e);

      }

   }

}

 

3.  Ports and Protocols

As a general rule each computer only has one Internet address. However, computers often need to communicate with more than one host at a time. For example, there may be multiple ftp sessions, and few web connections all running at the same time.

To make this possible the computer's network interface is logically subdivided into 65,536 different ports.   Note that ports are logical abstraction. That is, they do not represent anything physical like a serial or parallel port.

 

On Unix systems you must have certain access rights to listen for connections on ports between 1 and 1023.  Anyone can listen for connections on ports of 1025 to 65,535 as long as the port is not already occupied. (No more than one program can listen on a given TCP port at the same time.) However on Windows NT, Windows 95, and the Mac any user can listen to any port. No special privileges are required.

 

Any remote host can connect to a server that's listening on a port below 1024. Furthermore, multiple simultaneous connections may be made to a remote host on a remote port. for example, a high volume web server listening on port 80 may be processing several dozen connections at the same time, all connected to port 80.

 

Protocols

A protocol defines how two hosts talk to each other. For example, in radio communications a protocol might say that when one participant finished speaking, he or she says "Over" to tell the other end that it's OK to start talking. In networking a protocol defines what is and is not acceptable for one participant in a conversation to say to the other at a given moment in time.

 

There are as many different kinds of protocols as there are services that use them.  Some examples protocols are FTP, HTTP, SMTP, etc.

 

Many services run on well-known ports. This means that the protocol specifies that the service should or must use a particular port. For example http servers generally listen to port 80. FTP servers listen to port 21, SMTP servers listen for connections on port 25. Echo servers listen on port 7.  etc.

 

 

4.  Writing client applications using the URL class

A URL, short for "Uniform Resource Locator", is a way to unambiguously identify the location of a resource on the Internet. Some typical URLs look like:

http://www.javasoft.com/
http://www.macintouch.com:80/newsrecent.shtml
ftp://ftp.info.apple.com/pub/
mailto:elharo@metalab.unc.edu
telnet://utopia.poly.edu#section1

 

Most URLs can be broken into about five pieces, not all of which are necessarily present in a given URL. These are:

 

The java.net.URL class is used to represents a URL. It has constructors to create new URLs and it has methods to parse the different parts of a URL. However the heart of the class are the methods that allow you to get an InputStream from a URL so you can read data from a server.   Some of its constructors and methods are as follows:

public URL(String u) throws MalformedURLException

creates a URL object given the url u

public URL(String protocol, String host, String file)
throws MalformedURLException

creates a URL given the url components

public URL(String protocol, String host, int port,
 String file) throws MalformedURLException

similar to the above with the addition of port number

public String getProtocol()

returns the protocol part of the url

public String getHost()

returns the host name part of the url

public int getPort() 

returns the port part of the url or –1 if no port is specified.

public String getFile()

returns the file part of the url

public String getRef()

returns the reference part of the url or null

openStream()

opens the url as a stream source.  This can then be used to create a BufferedReader object to read from the URL

 

Example 2:  The following example reads data from a URL.

import java.net.*;

import java.io.*;

 

public class ReadFileFromURL{

 

   public static void main(String[] args) {

      String url = "http://www.ccse.kfupm.edu.sa/~bmghandi/002/ics201/project/books.txt";

 

      try {

         URL u = new URL(url);

         BufferedReader in = new BufferedReader(new InputStreamReader( u.openStream()));

         String input;

         while ((input = in.readLine()) != null)

            System.out.println(input);

      }

      catch (MalformedURLException e) {

         System.err.println(e);

      }

      catch (IOException e) {

         System.err.println(e);     

      }

   }

}

 

5.  Writing client applications using the Socket class

Socket is a logical communication channel enabling you to transfer data through a certain port.  Multiple sockets can be established using a single port as the following figure shows.

 

Essentially, a socket is used to perform the following operations:

 

  1. Connect to a remote machine
  2. Send data
  3. Receive data
  4. Close the connection

 

The java.net.Socket class allows you to perform all four fundamental socket operations.

Some of the constructors and methods of the Socket class are shown below:

public Socket(String host, int port) throws UnknownHostException, IOException
public Socket(InetAddress address, int port) throws IOException
public InputStream getInputStream() throws IOException
public OutputStream getOutputStream() throws IOException
public synchronized void close() throws IOException
public InetAddress getInetAddress()
public int getPort()

 

Notice that to create a socket to establish a connection to a certain host, we must know both the name of the host and the port on which the host provides the service we want.  Once the socket is created, we can use its getInputStream() and getOutputStream() methods to create a BufferedReader and a PrintWriter object for the purpose of reading and writing to the host.

 

Example 3:  The following example uses Socket to read data from a file on a given host.

import java.net.*;

import java.io.*;

 

public class HTTPClient {

 

  public static void main(String[] args) {

 

    int port = 80;

    String url = "http://www.ccse.kfupm.edu.sa/~bmghandi/002/ics201/project/books.txt";

 

      try {

         URL u = new URL(url);

         if (u.getPort() != -1) port = u.getPort();

         if (!(u.getProtocol().equalsIgnoreCase("http"))) {

           System.err.println("Sorry. I only understand http.");

           return;

         }

         Socket s = new Socket(u.getHost(), port);

         PrintWriter out = new PrintWriter(s.getOutputStream(), false);

         out.println("GET " + u.getFile() + " HTTP/1.0");

         out.println("Accept: text/plain, text/html, text/*\n");

         out.flush();

 

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

         String input;

         while ((input = in.readLine()) != null) {

           System.out.println(input);

         }

      }

      catch (MalformedURLException e) {

        System.err.println(url + " is not a valid URL");

      }

      catch (IOException e) {

        System.err.println(e);

      }

  }

}

 

Note:  In the above example, the HTTP protocol requires that the client must first issue a GET request indicating the file required followed by an ACCEPT statement indication the type of files it can accept.  The server then respond accordingly.

 

What is the advantage of using Socket instead of using URL?

 

6.  Writing server applications using the ServerSocket class

There are two ends to each connection: the client, that is the host that initiates the connection, and the server, that is the host that responds to the connection. Clients and servers are connected by sockets.

On the server side, a program waits for other hosts to connect to it. A server socket binds to a particular port on the local machine. Once it has successfully bound to a port, it listens for incoming connection attempts. When it detects a connection attempt, it accepts the connection. This creates a socket between the client and the server over which the client and the server communicate.

 

Multiple clients can connect to the same port on the server at the same time. Incoming data is distinguished by the port to which it is addressed and the client host and port from which it came. The server can tell for which service (like http or ftp) the data is intended by inspecting the port. It can tell which open socket on that service the data is intended by looking at the client address and port stored with the data.

 

No more than one server socket can listen to a particular port at one time. Therefore, since a server may need to handle many connections at once, server programs tend to be heavily multi-threaded. Generally the server socket listening on the port will only accept the connections. It then passes off the actual processing of connections to a separate thread.

 

Incoming connections are stored in a queue until the server can accept them. (On most systems the default queue length is between 5 and 50. Once the queue fills up further incoming connections are refused until space in the queue opens up.)

 

The java.net.ServerSocket Class

The java.net.ServerSocket class represents a server socket. It is constructed on a particular port. Then it calls accept() to listen for incoming connections. accept() blocks until a connection is detected. Then accept() returns a java.net.Socket object you use to perform the actual communication with the client.

 

Some of the constructors and methods of ServerSocket are as follows:

public ServerSocket(int port) throws IOException
public Socket accept() throws IOException
public void close() throws IOException

 

Example 4:  The following example implements an echo server.  A server that simply reads input from the client and echo it back.

import java.net.*;

import java.io.*;

 

public class EchoServer extends Thread {

   static final int DEFAULT_PORT = 5555;

   private Socket client;

  

   public EchoServer(Socket client) {

       this.client = client;

   }

    

   public void handleConnection() {

     String message=null;

     do {

        try {

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

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

         message = in.readLine();

         if (message.equalsIgnoreCase("exit")) {

            client.close();

            return;

         }

         else {  

            System.out.println("MessageReceived: "+message+"\n");

            out.println(message+"\n");

         }  

       } catch (IOException ioe) {

         System.out.println("IOException: " + ioe);

       }

     } while (message != null); 

   }

 

   public static void main(String[] args) {

      int port = DEFAULT_PORT;

      try {

         port = Integer.parseInt(args[0]);

       }

       catch (Exception e) {

       }   

      if (port<=0 || port >= 65536)

           port = DEFAULT_PORT;

          

      System.out.println("Echo Server has been started\nWaiting for Request\n");

       try {

         ServerSocket listener = new ServerSocket(port);

         while(true) {

           Socket s = listener.accept();

           System.out.println("Got connection from "+s.getInetAddress().getHostName()+"\n");

           EchoServer handler = new EchoServer(s);

           handler.handleConnection();

         }

       } catch (IOException ioe) {

         System.out.println("IOException: " + ioe);

       }

   }

}

 
The following is a client that can be used to test the echo server above.

import java.net.*; 

import java.io.*;

public class EchoClient {

  final static int DEFAULT_PORT = 5555;

  private String host;

  private int port;

 

  public EchoClient(String host, int port) {

    this.host = host;

    this.port = port;

  }

 

  public void connect() {

    try {

      Socket client = new Socket(host, port);

      handleConnection(client);

    } catch(UnknownHostException uhe) {

      System.out.println("Unknown host: " + host);

    } catch(IOException ioe) {

      System.out.println("IOException: " + ioe);

    }

  }

 

  public void handleConnection(Socket client) {

    String message = null;

  while (true) {

    try {

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

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

       BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));

       System.out.print("Enter message to echo or Exit to end : ");

       message = stdin.readLine();

       out.println(message);

       if (message.equalsIgnoreCase("exit"))

          return;

       else  

          System.out.println(in.readLine()+"\n");

     }

     catch (IOException e) {

      System.out.println("IOException ");

     }

    } 

  }

  public static void main(String[] args) throws IOException {

    String host = InetAddress.getLocalHost().getHostName();

    if (args.length > 0)

      host = args[0];

    int port = DEFAULT_PORT;

   try {

      port = Integer.parseInt(args[1]);

    }

    catch (Exception e) {

    }   

   if (port<=0 || port >= 65536)

        port = DEFAULT_PORT;

    EchoClient client = new EchoClient(host, port);

    client.connect();

  }

}

7.  Multi-threaded server

The implementation of the echo server in the example above has a serious problem.  If a client connect to the server, then any other client must wait until the first client is disconnected.  To improve on this, we make the handling of each client to be handled by a separate thread.  
 
Example 5:  The following example modifies example 4 by making it multi-threaded.

import java.net.*;

import java.io.*;

 

public class ThreadedEchoServer extends Thread {

    static final int DEFAULT_PORT = 5555;

   private Socket client;

  

   public ThreadedEchoServer(Socket client) {

       this.client = client;

   }

    

   public void run() {

     String message=null;

     do {

        try {

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

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

         message = in.readLine();

        

         if (message.equalsIgnoreCase("exit")) {

            client.close();

            return;

         }

         else {  

            System.out.println("MessageReceived: "+message+"\n");

            out.println(message+"\n");

         }  

       } catch (IOException ioe) {

         System.out.println("IOException: " + ioe);

       }

     } while (message != null); 

   }

 

   public static void main(String[] args) {

      int port = DEFAULT_PORT;

      try {

         port = Integer.parseInt(args[0]);

       }

       catch (Exception e) {

       }   

      if (port<=0 || port >= 65536)

           port = DEFAULT_PORT;

          

      System.out.println("Echo Server has been started\nWaiting for Request\n");

       try {

         ServerSocket listener = new ServerSocket(port);

         while(true) {

           Socket s = listener.accept();

           System.out.println("Got connection from "+s.getInetAddress().getHostName()+"\n");

           ThreadedEchoServer handler = new ThreadedEchoServer(s);

           handler.start();

         }

       } catch (IOException ioe) {

         System.out.println("IOException: " + ioe);

       }

   }

}

 

 

4.  Assignment

 

1.        Write a program that reads a string from the user.  If the string represents an IP address of a computer, the program should display the name of the computer.  If the input is a computer name, the program should display the IP address of the computer.

 

2.        The file quotes.txt contains a list of about 140 quranic, hadith and other Islamic quotations one quoate per line.  Write a Quotation server applications that:

·         first reads the data from the file into an array of strings.

·         it then listens for connection from client.

·         once a connection is established, the server sends a random quotation from the array to the client and disconnect from that client and listen for another client.

 

Note: Since a client does not spend too much time with the server, there is no need for threads.