INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM
ICS201, SECTIONS 52 (002
Semester)
INTRODUCTION TO COMPUTER SCIENCE
LAB # 11: Networking
Instructor: Bashir M. Ghandi
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:
|
used to instantiate an object of the class. The class has no constructor. |
|
used to get the address of the local computer. |
|
returns the name of the computer represented by the current InetAddress object |
|
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); } } } |
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.
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.
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:
|
creates a URL object given the url u |
|
creates a URL given the url components |
|
similar to the above with the addition of port
number |
|
returns the protocol part of the url |
|
returns the host name part of the url |
|
returns the port part of the url or –1 if no port
is specified. |
|
returns the file part of the url |
|
returns the reference part of the url or null |
|
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); } } } |
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:
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?
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.)
java.net.ServerSocket
ClassThe 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(); } } |
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);
} } } |
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.