PAGE
1Input output for a file tutorialStreams and File I/O
In this tutorial we study the following concepts:
Text File I/O
Techniques for a file: Class File
Binary File I/O
File Objects and File Name
Note: For question 4 of the midterm you only need to look at the sections 2.2 and 2.3. I do not think you need java class: StringTokenizer. But I just added a small section about it to the end of this tutorial.
So far we learned keyboard/screen I/O. It is time to learn File I/O.
1 An Overview of stream and file I/O
A stream is an object that either outputs data or inputs data. The Java System.out is a stream object that outputs data on the screen.
As our program gets bigger and bigger we may need to enter a lot of data every time we run our program. We also may have a lot of data as the output of the program. It is not practical to enter a sizable input from the keyboard. Therefore, we save the data in a file and let our program to input from this file. Similarly, it is not practical to look at a sizable output. Moreover, we may need to save the output for further study. Therefore, we let our program to output to a file.
We have two kinds of I/O files: Text files and binary files. A text file is readable and understandable by human, but a binary file is not. The size of a text file is bigger than the size of a binary file. We can write arrays without using a loop into a binary file. We can also write objects to a binary file.
2 Text-File I/O
In this section we learn how to input from a text file and how to output to a text file. We first look at output instructions for a text file.
2.1 Text-File Output with PrintWriter class.
To be able to write to a file we need the Java class PrintWriter. This class is in JDK java.io, therefore we need to import it . Another class that we need is : FileOutputStream. This class also is in java.io. A file output stream is an output stream for writing data to a File.
Example 1. The following program to write an integer, a floating point number, a Boolean value and a string into a text file.
import java. io. PrintWriter;
import java. io. FileNotFoundException;
publicclass Main {
publicstaticvoid main( String[] args) {
PrintWriter out = null;
try {
out = new PrintWriter("out.txt");
} catch( FileNotFoundException e) {
System. out. println("Error: opening the file out.txt");
System. exit( 0);
}
out.println(-12);
out.println(25.5);
out.println(true);
out.println("John Doe.");
//Note that we also can write:
out.println(-12+"\n"+ 25.5 + "\n" + true + "\n" + "John Doe.");
out.close();
} }
The content of the file out.txt would be:
-12
25.5
true
John Doe.
-12
25.5
true
John Doe.
Description:
First we need to declare a variable that refers to and object of class PrintWriter. This class has several constructors. One of them needs the name of the output file on the hard drive (or other storages): out = new PrintWriter("out.txt")
This instruction co.
PAGE 1Input output for a file tutorialStreams and File IOI.docx
1. PAGE
1Input output for a file tutorialStreams and File I/O
In this tutorial we study the following concepts:
Text File I/O
Techniques for a file: Class File
Binary File I/O
File Objects and File Name
Note: For question 4 of the midterm you only need to look at
the sections 2.2 and 2.3. I do not think you need java class:
StringTokenizer. But I just added a small section about it to the
end of this tutorial.
So far we learned keyboard/screen I/O. It is time to learn File
I/O.
1 An Overview of stream and file I/O
A stream is an object that either outputs data or inputs data. The
Java System.out is a stream object that outputs data on the
screen.
As our program gets bigger and bigger we may need to enter a
lot of data every time we run our program. We also may have a
lot of data as the output of the program. It is not practical to
enter a sizable input from the keyboard. Therefore, we save the
data in a file and let our program to input from this file.
Similarly, it is not practical to look at a sizable output.
Moreover, we may need to save the output for further study.
Therefore, we let our program to output to a file.
We have two kinds of I/O files: Text files and binary files. A
text file is readable and understandable by human, but a binary
file is not. The size of a text file is bigger than the size of a
binary file. We can write arrays without using a loop into a
binary file. We can also write objects to a binary file.
2. 2 Text-File I/O
In this section we learn how to input from a text file and how to
output to a text file. We first look at output instructions for a
text file.
2.1 Text-File Output with PrintWriter class.
To be able to write to a file we need the Java class PrintWriter.
This class is in JDK java.io, therefore we need to import it .
Another class that we need is : FileOutputStream. This class
also is in java.io. A file output stream is an output stream for
writing data to a File.
Example 1. The following program to write an integer, a
floating point number, a Boolean value and a string into a text
file.
import java. io. PrintWriter;
import java. io. FileNotFoundException;
publicclass Main {
publicstaticvoid main( String[] args) {
PrintWriter out = null;
try {
out = new PrintWriter("out.txt");
} catch( FileNotFoundException e) {
System. out. println("Error: opening the file out.txt");
System. exit( 0);
}
out.println(-12);
out.println(25.5);
out.println(true);
out.println("John Doe.");
//Note that we also can write:
out.println(-12+"n"+ 25.5 + "n" + true + "n" + "John
Doe.");
3. out.close();
} }
The content of the file out.txt would be:
-12
25.5
true
John Doe.
-12
25.5
true
John Doe.
Description:
First we need to declare a variable that refers to and object of
class PrintWriter. This class has several constructors. One of
them needs the name of the output file on the hard drive (or
other storages): out = new PrintWriter("out.txt")
This instruction connects the variable: out to the actual name of
the file: out.txt on the hard disk. We need to include this
instruction in a try-catch block because we may not have space
on the hard disk (or the storage is not writeable). In this case
the program cannot create a file on the disk. The name of the
variable: out is optional. After establishing this connection we
use all the print and println that we use for standard output. The
standard output is the display screen. At the end we mustclose
the file. In reality when our program wants to write data to a
file, it first writes it to the output buffer (An array of
4. characters). Then the I/O system of the computer writes it to the
file. If we do not close, or flush the data, the system won’t write
the last part of the data into file.
Exercise 1: Change the program in example 1 such that the
program asks the user to enter the name of the output file. The
program then must create a file with this name on the hard
drive.
Appending to a text file
Every time we run the program in example 1 it removes the file
out.txt from the hard drive, creates an empty file with this
name, and outputs data to that name. To be able to append the
data we need to use another constructor of the class PrintWriter.
Example 2: The following program appends data to a file
provided we run it more than one time.
import java.io.FileOutputStream;
import java. io. PrintWriter;
import java. io. FileNotFoundException;
publicclass Main {
publicstaticvoid main( String[] args) {
PrintWriter out = null;
try {
out = new PrintWriter( new FileOutputStream("out.txt",
true));
} catch( FileNotFoundException e) {
System. out. println("Error: opening the file out.txt");
System. exit(0);
}
out.println("Hell World");
out.close();
}
}
Description:
This constructor of the class PrintWriter accepts an object of
the type of the java class: FileOutputStam. This class in turn
5. has a constructor that needs the name of the file on the hard
disk and/or Boolean value. If the Boolean value is true the
program appends to the file. If it is false or we do not write it
the program creates a new file. In summary:
a) With: new PrintWriter( new FileOutputStream("out.txt",
true)). The program appends:
b) With:
new PrintWriter( new FileOutputStream("out.txt", false));
Or:
new PrintWriter( new FileOutputStream("out.txt"));
The program deletes the file (if any) and creates a new file.
2.2 Reading from a Text-File
We now learn how to read from a text file.
Example 3: The following program reads two lines from a file
named: in.txt and display them on the screen:
import java. util. Scanner;
import java. io. File;
publicclass Main {
publicstaticvoid main( String[] args) {
Scanner inputStream = null;
try{
inputStream = new Scanner( new File("in.txt"));
}catch(Exception e){
System.out.println("Error: " + e.getMessage());
System.exit(0);
}
6. String line = inputStream. nextLine();
System. out. println(line);
line = inputStream. nextLine();
System. out.println(line);
inputStream.close();
}
}
First Sample Output:
Error: in.txt (The system cannot find the file specified)
In this sample screen output we did not created the input file.
Therefore when instruction:
inputStream = new Scanner( new File("in.txt"));
Gets executed and an exception occurs and the control of
execution jumps to the catch-block and prints a message from
the parameter: e.
Note that the java class Scanner has a different type of
argument for its constructor. The segment: System.in was for
reading from the standard input (i.e. the keyboard). In the above
case the constructor has an object of the type java class: File.
This class accepts a file name for its constructor. If this file
name does not exist on the hard disk the execution of the above
statement throws an exception.
Second Sample Output:
Hello
Have a nice day
In this sample we have a file on the disk with the name in.txt
and the file has two lines (or more). The file contains three
lines:
Hello
7. Have a nice day
I may not show on the output
Note that the program only reads the first two lines.
We may have a situation that we do not have enough data value
in an input file. Let us take care of this situation.
Exercise: Make the file read protected and try the above
program.
Example 4: The following program reads five lines from an
input file:
import java.util.Scanner;
import java.io.File;
publicclass Main {
publicstaticvoid main( String[] args) {
Scanner inputStream = null;
try{
inputStream = new Scanner( new File("in.txt"));
}catch(Exception e){
System.out.println("Error: " + e.getMessage());
inputStream.close();
System.exit(0);
}
for(int i = 1; i <= 5; i++){
String line = inputStream. nextLine();
System.out.println(line);
}
inputStream.close();
}
}
Sample Output:
Hello
Have a nice day
8. I may not show on the output !
Exception in thread "main" java.util.NoSuchElementException:
No line found
at java.util.Scanner.nextLine(Unknown Source)
at Main.main(Main.java:14)
The catch block is for the time the file does not exist. As we see
we need to add the exception: NoSuchElementException for the
case we do not have enough data in the file.
Example 5: The following program is the same as the one in
example 4 but our program controls the exception process rather
than Java Virtual Machine (JVM):
import java.util.NoSuchElementException;
import java. util. Scanner;
import java. io. File;
import java.io.FileNotFoundException;
publicclass Main {
publicstaticvoid main( String[] args) {
Scanner inputStream = null;
try{
inputStream = new Scanner( new File("in.txt"));
for(int i = 1; i <= 5; i++){
String line = inputStream. nextLine();
System. out. println(line);
}
}catch(FileNotFoundException e){
System.out.println("Error: " + e.getMessage());
}
catch(NoSuchElementException e){
9. System.out.println("Error: " + e.getMessage());
}
inputStream.close();
System.out.println("The end of the program.");
}
}
Sample Output:
Hello
Have a nice day
I may not showing on the output !
Error: No line found
The end of the program.
Description:
In the fourth iteration of the for-loop the program tries to read
the fourth line from the input file. But no more line exist and
the program throws an exception which is caught by the second
catch block. Unlike example 4 the execution does not terminates
and the control of execution continues the execution of the rest
of the program.
Exercise 2: Write a program to read integers from an input file
and displays the average of those numbers.
Note: The file can have any numbers of integers (including no
number in the file).
Exercise 3: The following program reads an integer for n and
then n decimal numbers from the keyboard. The program sorts
the numbers and displays them on the screen. Change the
program to read all numbers from an input file and store the
sorted numbers into an output file.
Restrictions: The program should ask the user for the name of
the input and output file.
import java.util.*;
10. publicclass Main {
publicstaticvoid main( String[] args) {
Scanner keyboard = new Scanner( System.in);
System.out.print("How many numbers? ");
int n = keyboard.nextInt();
float a[] = newfloat[n];
System.out.println("Enter " + n + " numbers:");
for(int i = 0; i < a.length; i++)
a[i] = keyboard.nextFloat();
sort(a);
System.out.println("Sorted list:");
for(int i = 0; i < a.length; i++)
System.out.println(a[i]);
}
privatestaticvoid sort(float[] a){
float smaller;
int index;
for(int i = 0; i < a.length; i++){
index = i;
smaller = a[i];
for(int j = i + 1; j < a.length; j++)
if(smaller > a[j]){
smaller = a[j];
index = j;
}
a[index] = a[i];
a[i] = smaller;
11. }
}
}
2.3 Techniques for any file
If a file is in a separate folder than our project folder we need to
give the complete path. Suppose in example 5 the file is in a
separate folder named: Temp and this folder is in the C drive.
The path for this file is:
C:Temp
We give this path in either two ways:
a) inputStream = new Scanner( new File("C:/Temp/in.txt"));
b) inputStream = new Scanner( new File("C:Tempin.txt"));
In the second format since backslash is used for escape
characters such az n, t we need to use a double-backslash.
If the file name is in variable such as: fileName we need to
write:
inputStream = new Scanner( new File("C:/Temp/" + fileName));
The java class File has a number of methods. Some of them are:
In the following program we use these methods and more:
Example 6: The following program tests the above methods.
You need to create four text files.
publicclass Main {
publicstaticvoid main( String[] args) {
File f1 = new File("file1.txt");
File f2 = new File("file2.txt");
File f3 = new File("file3.txt");
File f4 = new File("file4.txt");
//The following if-else statement does not work in Windows.
It works in LINUX/UNIX
if(f1.canRead())
12. System.out.println("File file1.txt is readable.");
else
System.out.println("File file1.txt is read protected.");
if(f2.canWrite())
System.out.println("File file2.txt is writeable.");
else
System.out.println("File file2.txt is write protected");
if(f3.delete())
System.out.println("File file3.txt is now deleted");
else
System.out.println("File file3.txt does not exist to delete.");
if(f3.exists())
System.out.println("File file3.txt exists");
else
System.out.println("File file3.txt does not exists");
System.out.println("There is a file on the disk with the name:
" + f4.getName());
System.out.println("Its path is: " + f4.getPath());
System.out.println("Its length which is the number of
characters is: " +
f4.length());
}
}
Description: We change the attributes of a file on the disk by
right clicking on it and changing its properties.
3 Basic binary files
Since a binary file stores data in the same format as computer
13. (i.e in binary numbers), it is a more efficient file for processing.
Two Java classes handle binary file I/O, the
ObjectOutputStream and the ObjectInputStream. The output
methods are writeInt, writeDouble, writeChar, writeBoolean,
and writeUTF (for string), etc.Binary files are more compact
than text files.
Example 7: The following program creates binary file writes
some integer into the file.
import java. io. FileOutputStream;
import java. io. ObjectOutputStream;
import java. io. FileNotFoundException;
import java. io. IOException; import java. util. Scanner;
publicclass Main {
publicstaticvoid main( String[] args) {
String fileName = "numbers.dat";
try {
ObjectOutputStream outputStream = new ObjectOutputStream(
new FileOutputStream(fileName));
Scanner keyboard = new Scanner( System. in);
System. out. println("Enter nonnegative integers.");
System. out. println("Place a negative number at the end.");
int anInteger;
do {
anInteger = keyboard. nextInt();
outputStream.writeInt(anInteger);
} while ( anInteger >= 0);
14. System. out. println("Numbers and sentinel value");
System. out. println("written to the file " + fileName);
outputStream. close();
} catch( FileNotFoundException e) {
System. out. println("Problem opening the file " + fileName);
} catch( IOException e) {
System. out. println("Problem with output to file " + fileName);
}
}
}
Sample Output
Enter nonnegative integers.
Place a negative number at the end.
1 2 3 -1
Numbers and sentinel value
written to the file numbers.dat
Description:
The instruction:
ObjectOutputStream outputStream = new ObjectOutputStream(
new FileOutputStream(fileName))
Creates an output stream. The constructor of the class:
ObjectOutputStream needs an object of the type:
FileOutputStream. The constructor of this class in turn needs a
file name. The following loop repeatedly reads an integer from
the keyboard and writes to the binary file:
do {
anInteger = keyboard. nextInt();
outputStream.writeInt(anInteger);
15. } while ( anInteger >= 0);
Since a binary file is byte oriented we basically should say how
many bytes we like to write to or read from the file. In the
above loop the instruction: outputStream.writeInt(anInteger).
writes data of the size of an integer to the file. The size of an
integer is 8 bytes. To clarify this more let us change this
instruction to:
outputStream.writeChar(anInteger);
In this case only part of these 8 bytes (i.e. 2 bytes) will be
written.
The class outputStream has a number of methods. Some of them
are:
Example 8:The following program practices all the above
“write” methods:import java.io.*;
publicclass Main{
publicstaticvoidmain(String[] args) {
try{
ObjectOutputStream st = new ObjectOutputStream(
new FileOutputStream("out.dat"));
st.writeInt(-5);
st.writeDouble(12.5);
st.writeChar('A');
st.writeBoolean(true);
st.writeUTF("John Doe.");
st.close();
}catch(IOException e){
System.out.println(
"Error: Cannot create the file.");
System.exit(0);
}
}
}
16. Description: We are writing all types of data into the file:
out.dat.
The program does not have any instruction to display data. In
order to find whether we have written all of these data into this
file we need to read from the file and display them on the
screen.
We must read the same way we wrote. The
class:ObjectInputStream is used to read from a binary file and
has similar methods. Some of them are:
Example 9:The following program reads data from the binary
file out.dat in the same order and same size and displays on the
screen.
import java.io.*;
publicclass Main{publicstaticvoidmain(String[] args) {try{
ObjectInputStream st = new ObjectInputStream(new
FileInputStream("out.dat"));
int i = st.readInt();
double d = st.readDouble();
char c = st.readChar();
boolean b = st.readBoolean();
String s = st.readUTF();
st.close();
System.out.println(i+"n"+d+"n"+ c + "n" + b + "n" + s);
}catch(IOException e){ //or
ExceptionSystem.out.println("Error: Make sure the file exists in
the " +
"current folder.");
}
}
}
Sample output:
-5
17. 12.5
A
true
John Doe.
Description: Note that any data value and its size that has
written to the file in example 8 are read from the file with the
same size and order.
Exercise 4: Change the above program to read data in the
following order:
char c = st.readChar();
String s = st.readUTF();boolean b = st.readBoolean();
char c = st.readChar();double d = st.readDouble();
int i = st.readInt();
Exercise 5: The following program generates a random positive
integer for n and generates n floating number and saves them in
a file named: in.dat. The program displays the biggest, smallest
numbers and the average of all n floating numbers.
Change the program to read from the binary file binaryIn.dat
and displays the biggest, smallest numbers and the average of
all n floating numbers.
import java. util. Scanner;
import java.io.File;
publicclass Main {
publicstaticvoid main( String[] args) {
Scanner inputStream = null;
int biggest= 0;
int smallest = 0;
int sum = 0;
int count = 0;
try{
18. inputStream = new Scanner( new File("in.txt"));
biggest = inputStream. nextInt();
count++;
smallest = biggest;
sum = biggest;
while(true){
int x = inputStream.nextInt();
count++;
sum = sum + x;
if(x > biggest)
biggest = x;
if(x < smallest)
smallest = x;
}
}catch(Exception e){
System. out. println("The biggest number is: " +
19. biggest);
System. out. println("The biggest number is: " +
smallest);
System. out. println("The sum is: " + sum);
System. out. println("The average is: " +
(double)sum/count);
}
inputStream.close();
}
}
5 Binary Files I/O with Objects and Arrays
The binary file I/O can handle records (i.e. more than one item
at a time). A record is object of a class. To use this class for
binary I/O files we must make the class serializable. The
serialization interface has no methods. This interface is used to
make a class serializable. By making a class serializable we can
write the objects to a binary file.
To write a record (object) to the file we use Java method
writeObject. To read a record from the file we use Java method
readObject.
Example 10: The following program writes a record of a person
into a binary file and then read from the binary file and display
the record on the screen. The record has a name, age, and ss#.
20. import java.io.*;
publicclass Person implements Serializable{
staticfinallongserialVersionUID = 12;
private String name;
privateint age;
private String ss;
public Person(String name, int age, String ss){
this.name = name;
this.age = age;
this.ss = ss;
}
public String getName(){
return name;
}
publicint getAge(){
return age;
}
public String getSS(){
return ss;
}
}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&
import java.io.*;
publicclass Main{
publicstaticvoid main(String[] args) {
output();
input();
}
publicstaticvoid output(){
Person p = new Person("John Doe", 45, "123456789");
try{
ObjectOutputStream st = new ObjectOutputStream(
21. new FileOutputStream("out.dat"));
st.writeObject(p);
st.close();
}catch(Exception e){
System.out.println("Error 1: " + e.getMessage());
System.exit(0);
}
}
publicstaticvoid input(){
try{
ObjectInputStream st = new ObjectInputStream(
new FileInputStream("out.dat"));
Person p = (Person) st.readObject();
System.out.println(p.getName() + ", " + p.getAge() + ",
" +
p.getSS());
}catch(Exception e){
System.out.println("Error 2: " + e.getMessage());
System.exit(0);
}
}
}
Sample output:
John Doe, 45, 123456789
Description:
The method: output()creates an object of the type: Person,
passing John Doe, 45, and 123456789 as a name, an age, and an
ss# to the constructor. The statement: st.writeObject(p)writes
this object to a binary file.
22. The method: input()reads a number of bytes from the binary file
and display them. The number of the bytes is the size of the
instant variables name, age, and ss in the class Person. Note that
it is the casting in: (Person) st.readObject() that tells the control
of execution how many bytes should be read from the file.
Array Objects in Binary Files
We now extend the above program to write an array into a
binary file. Note that since array itself is an object we can write
and read the whole array. We do not need to write a loop to
write/read each element of the array for a binary file. However
for text files we have to use loops.
Example 11: The following program write an array of objects,
each of type class: Person into a binary file and then reads the
array from the binary file and displays the elements of the array
on the screen.
import java.io.*;
publicclass Main{
publicstaticvoid main(String[] args) {
output();
input();
}
publicstaticvoid output(){
Person[] p = new Person[3];
p[0] = new Person("John Doe", 45, "123456789");
p[1] = new Person("Jane Doe", 39, "456789999");
p[2] = new Person("James Bond", 75, "993456789");
try{
ObjectOutputStream st = new ObjectOutputStream(
new FileOutputStream("out.dat"));
st.writeObject(p);
st.close();
23. }catch(Exception e){
System.out.println("Error 1: " + e.getMessage());
System.exit(0);
}
}
publicstaticvoid input(){
try{
ObjectInputStream st = new ObjectInputStream(
new FileInputStream("out.dat"));
Person[] p = new Person[3];
p = (Person[]) st.readObject();
for(int i = 0; i < p.length; i++)
System.out.println(p[i].getName() + ", " +
p[i].getAge() + ", " + p[i].getSS());
}catch(Exception e){
System.out.println("Error 2: " + e.getMessage());
System.exit(0);
}
}
}
Sample Output:
John Doe, 45, 123456789
Jane Doe, 39, 456789999
James Bond, 75, 993456789
Description:
There are two important lines in this program:
a) We write: st.writeObject(p).to write the whole array in to the
24. binary file (We cannot do this with a text file). We do not write:
for(int i = 0; i < p.length; i++)
st.writeObject(p[i]);
b) We write: p = (Person[]) st.readObject() to read from the file
to all the elements of the array. Note the casting is not:
(Person). It is (Person[]). We do not write:
for(int i = 0; i < p.length; i++)
st.readObject(p[i]);
String Tokenizer
I just included this section to learn the string tokenizes. There
are programs that we need to read strings and extract the words
of each string (The exercise at the end of this lecture is of this
nature). The Java class StringTokenizer can be used to deal with
this problem.
Example 12. A program to read a sentence and prints every
word.
import java.util.*;
import java.io.*;
publicclass Main{
publicstaticvoidmain(String[] args) {
Scanner key = new Scanner(System.in);
System.out.println("Enter a line");
String s = key.nextLine();
StringTokenizer tok = new StringTokenizer(s);
while(tok.hasMoreTokens()){
String word = tok.nextToken();
System.out.println(word);
}
}
}
25. Sample Output:
Enter a line
This part is not in this section in your book.
This
part
is
not
in
this
section
in
your
book.
Description:
The instruction: StringTokenizer tok = new StringTokenizer(s)
splits the string into words. Now in the variable: tok we have
these words. The points of segmentation of the words is
character space. For example the space between the words: This
and part, or the space between the words: part and is. In the
while-loop:while(tok.hasMoreTokens()){
String word = tok.nextToken();
System.out.println(word);
}
The method: tok.hasMoreTokens() returns true as long as there
is a next token (a word). The method: tok.nextToken() gets the
next token (word).
1
Lecture 2
The Socket API Continued
For Chapter 5 & 6 of Distributed Computing: Principles and
Applications
26. For Chapter 5
You need to read your book and practice the exercises. This is
just an extra note for the chapter.
Read this lecture after you have read chapters 5&6 of your
second textbook.
Introduction
From these two chapters I clarify the concepts that are not
explained in chapter 4. The client-server program which I
explained in detail is about a concurrent server (section 5.5).
This is a server that services several clients.
Most of the programs are straightforward. However there are
programs that require you enter data in a command-line for the
parameters of the method: main. To add data values for the
parameter of this method follow the steps below:
1. From the menu bar click on Run ( Run Configuration and
click on the tab: Arguments to see:
2. Enter your data values in the window labeled: Program
arguments. If you have more than one data value separate them
by a space.
5.1, 5.2, 5.3
The client server programs in these sections are similar to the
ones in chapter 4. They even are easier than your previous
project.
Daytime Client-Server Using Stream-Mode Sockets:
The program in the book is rather sizeable. I rewrote this
program in smaller and more understandable fashion.
27. Example 1: In the following program the server sends the time
of the day to the client using connection oriented datagram:
The server:
import java.io.*;
import java.net.*;
import java.util.*;
publicclass MyServer {
publicstaticvoid main(String[] args) throws IOException {
ServerSocket serverSocket = null;
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
System.out.println("Daytime server ready.");
try {
serverSocket = new ServerSocket(4321);
while(true){
clientSocket = serverSocket.accept();
in= new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
in.readLine();
System.out.println("Request received.");
out = new PrintWriter(clientSocket.getOutputStream(),
true);
Date timestamp = new Date ();
System.out.println("timestamp sent:
"+timestamp.toString());
out.println(timestamp.toString());
}
} catch (IOException e) {
System.out.println("Error: " + e);
in.close();
28. out.close();
clientSocket.close();
serverSocket.close();
System.exit(0);
}
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
}
The client:
import java.io.*;
import java.net.Socket;
publicclass MyClient {
publicstaticvoid main(String[] args) throws IOException {
Socket clientSocket = null;
BufferedReader in = null;
System.out.println("Welcome to the Daytime client.");
try {
clientSocket = new Socket(“localhost”, 4321);
PrintWriter out = new
PrintWriter(clientSocket.getOutputStream(), true);
out.println("");
in = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
String s = in.readLine();
System.out.println("Here is the timestamp received from the
server: "+s);
in.close();
clientSocket.close();
out.close();
clientSocket.close();
}catch (IOException e) {
System.out.println("Error: " + e);
}
29. }
}
Description:
The above program actually is about half the project 1. In
project 1 client and server send messages but in this program
the client sends a null string (string with no character: “”), gets
the time stamp from the server and terminates (unlike in project
1 that does not terminate).
The server:
· in.readLine(): The server has to wait on this line until the
client sends a null string.
· Date timestamp = new Date (): Creates a date object.
· out.println(timestamp.toString()): Sends the date to the client.
The client:
· out.println(""): Sends a null string to the server. The server is
waiting on: in.readLine() . The server reads this null string and
the control in the server moves to the next instruction.
· String s = in.readLine(): Reads (receives) the timestamp from
the server.
· System.out.println("Here is the timestamp received from the
server: "+s): The client prints the timestamp.
Daytime Client-Server Using Connectionless Datagram Sockets:
I do not explain this program. It is similar to the one in example
1.
Exercise 1: Convert the program in example 1 to a program
30. using connectionless datagram socket.
5.4 Connection-Oriented and Connectionless Servers
There are systems that need to be sure a message sent by a
client has been received by a server. In this case the server
should echo the message back to the client.
Example 2: In the following client-server program when the
server receives a message from a client it echoes back the
message to the client.
The server:
import java.io.*;
import java.net.*;
publicclass MyServer {
publicstaticvoid main(String[] args) throws IOException {
try {
finalint MAX_LEN = 100;
byte[] buffer = newbyte[MAX_LEN];
int port = 1234;
DatagramPacket datagram = new DatagramPacket(buffer,
buffer.length);
DatagramSocket clientSocket = new DatagramSocket(port);
System.out.println("Echo server ready.");
while(true){
clientSocket.receive(datagram);
String message = new String(buffer);
System.out.println("From client: " + message);
clientSocket.send(datagram);
31. }
} catch (IOException e) {
System.out.println("Error: " + e);
System.exit(0);
}
}
}
The client:
import java.io.*;
import java.net.*;
import java.util.*;
publicclass MyClient {
publicstaticvoid main(String[] args) throws IOException {
System.out.println("Welcome to the Echo client.");
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter a message to send or a period to quite:
");
String message = keyboard.nextLine();
while(! message.equals("."))
try {
byte[] buffer = message.getBytes();
int port = 1234;
InetAddress host = InetAddress.getByName("localhost");
DatagramSocket serverSocket = new DatagramSocket();
32. DatagramPacket datagram=new
DatagramPacket(buffer,buffer.length,host, port);
serverSocket.send(datagram);
message = new String(buffer);
serverSocket.receive(datagram);
System.out.println("From server: "+ message);
System.out.print("Enter a message to send: ");
message = keyboard.nextLine();
} catch (IOException e) {
System.out.println("Error: " + e);
System.exit(0);
}
}
}
Description:
The server:
The while-loop iterates forever.
clientSocket.receive(datagram): When the server starts it blocks
on this instruction until the client sends a message. Once the
client sends a message it is stored in the variable: datagram.
clientSocket.send(datagram): Sends the same message back to
the client.
33. The client:
The client keeps sending messages to the server until the user
enters a period.
serverSocket.send(datagram): Sends a message to the server.
The pro then blocks on: serverSocket.receive(datagram).until
the server echoes back the message. In this case this instruction
receives it. The echoed message is stored in the variable:
datagram. The next instruction displays the echoed message.
5.5 Iterative Server and Concurrent Server
In general a server does not just servers one client. Normally
they serve many clients. In this section take a look at such
server. What we need is let the server create a java thread on
the request of each client and code the thread to do the task
requested by the client. To refresh your memory I first present a
simple example to show how to generate threads in java.
Example 3: The following program creates two threads. Each of
them adds two numbers. The method: main takes these two sums
and multiply them:
publicclass Main {
publicstaticvoid main(String[] args) {
MyThread m1 = new MyThread(2, 3);
MyThread m2 = new MyThread(4, 5);
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m2);
35. publicclass MyThread implements Runnable{
privateint a, b;
publicint result;
public MyThread(int a, int b){
this.a = a;
this.b = b;
}
publicvoid run(){
result = a + b;
}
}
Output:
45
Description:
The class Main:
The Java Virtual Machine (JVM) always creates a thread to
execute method: main. This is not a thread we create in our
program. This thread has been there from the very first java
program we have written. I call this thread the: main thread.
MyThread m1 = new MyThread(2, 3) and MyThread m2 = new
MyThread(4, 5): Creates two objects where m1 and m1 are
referring to.
Thread t1 = new Thread(m1): Creates a thread for: t1 to execute
the method: run that the object: m1 is referring to. Note that:
The control of execution does not start the execution of method:
36. run until the control executes: t1.start().
Thread t2 = new Thread(m2): Creates a second thread to execute
the method: run that the object: m2 is referring to.
t1.start(): The control of execution starts executing the thread:
t1. The thread adds 2 and 3 and stores in the public variable:
result in class: MyThread.
t2.start(): The control of execution starts executing the thread:
t2. The thread adds 4 and 5 and stores in the public variable:
result in class: MyThread.
t1.join():The join method allows the main thread blocks on this
instruction until the execution of the thread t1 is completed.
t2.join():The main thread blocks on this instruction until the
execution of the thread t2 is completed.
System.out.println((m1.result*m2.result)): The main thread
multiplies 5 and 9 and displays.
The class MyThread:
publicclass MyThread implements Runnable{: Runnable is a
java interface. When a class (like: MyThread) implements a java
interface (here Runnable) all the methods of the interface must
be defined. In the interface: Runnable there is a method named:
run whose signature is: publicvoid run(). You must not change
this signature. It must not have any parameter and must be of
type void. When the control in the main thread executes:
t1.start() (or t2.start()) it executes the method: run.
Note: In class: MyThread in the instruction: this.a = a .the left
side refers to the instance variable: a but the right side refers to
parameter: a.
Exercise 2: Comment or remove the try-catch block of class
37. MyThread and run the program. Do you get the right output?
Why? Why not?
We now are in a position to write a client-server program that
the server can handle several clients.
Example 4: The server in following program creates a thread for
any client. The server echoes back a message sent by a client.
import java.io.*;
import java.net.*;
publicclass MyServer {
publicstaticvoid main(String[] args)throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4321);
} catch (IOException e) {
System.out.println("Error: " + e);
System.exit(0);
}
while(true){
38. MyThread a = new MyThread(serverSocket.accept());
Thread t = new Thread(a);
t.start();
}
}
}
import java.io.*;
import java.net.*;
publicclass MyThread implements Runnable{
Socket clientSocket;
public MyThread(Socket clientSocket){
this.clientSocket = clientSocket;
}
publicvoid run(){
try{
PrintWriter out = new
PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new
40. System.out.println("Error from the thread: " + e);
}
}
}
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
publicclass MyClient {
publicstaticvoid main(String[] args) throws IOException {
Scanner keyboard = new Scanner(System.in);
try {
Socket clientSocket = new Socket("localhost", 4321);
PrintWriter out = new
PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
System.out.print("Enter a message to send or a period to quite:
");
String s = keyboard.nextLine();
while(!s.equals(".")){
41. out.println(s);
s = in.readLine();
System.out.println("From server: "+ s);
System.out.print("Enter a line or a period to quit: ");
s = keyboard.nextLine();
}
clientSocket.close();
out.close();
in.close();
}catch (IOException e) {
System.out.println("Error: " + e);
System.exit(0);
}
}
}
Description:
The server:
The server iterates forever. For any new client the while-loop
iterates once.
· The class MyServer:
42. ServerSocket serverSocket = new ServerSocket(4321): Open
one port. Every client communicates with the server through
this port.
In the while-loop we have:
MyThread a = new MyThread(serverSocket.accept()): Creates
an object of the class: MyThread. The argument:
serverSocket.accept() makes the server to wait until a client
connects to this server. The call to method: returns a socket. We
are passing this socket to the constructor of the class MyThread.
Thread t = new Thread(a): Argument: a refers to the object
made in the previous instruction. We make this object to be a
new thread.
Finally we start the execution of the thread.
· The class MyThread:
The code that we used to write in the method: main of a server
we have in method: run.
The client:
The client has one class:
· The class MyClient:
This is similar to the client you wrote in project 1. It also is a
version of the echo server in example 2 but it is a connection-
Oriented server (see also pages: 160-165). The client repeatedly
sends a message to the server and the server sends it back.
How to run these programs:
Make a work station for the server that has two classes:
MyServer and MyThread.
43. Make several work stations with the client class: MyClient.
Run the server.
Run all of the clients.
5.6 State fulServers
Read this section.
5.7 Global State Information
This type of information in a server is accessible by all the
clients. The server in page 170 has a static variable named:
counter. The server increments: counter when a new thread is
made for a new client. Since this variable is static we need to be
sure no two or more clients access this variable at the same
time. That is why the following method is defined as a
synchronized method. Only one thread at a time can enter to a
synchronized method in Java.
staticprivatesynchronizedvoidincrement( ){
counter++;
}
For Chapter 6
In the previous chapter two threads communicate with each
other. In this chapter we like to design client-server program
such that a group of server/client programs communicate.
6.1 Unicast versus Multicast
A one-to-one communication like in the previous chapter is
called Unicast. When a group of threads communicate is called
Multicast. See Figure 6.1, page 183.
44. 6.2 An Archetypal Multicast API
The multicasting programs should have the following
capability:
· Join: To include a new member.
· Leave: To remove a member desire to leave.
· Send: To send a message from one member to others.
· Receive: To receive messages from the members of the group.
6.3 Connectionless versus Connection-Oriented Multicast
Connectionless IPC is more efficient than Connection-oriented.
Suppose we have n processes (programs) to communicate. A
process needs to send messages to the other n-1 processes.
Therefore in a connection-oriented protocol we need to have n *
(n -1) connections. When n is large like 100 we need 9900
connections.
6.4 Reliable Multicasting versus Unreliable Multicasting
This is a very brief explanation of the section. For more detail
read pages 185-188.
Communication between processes (programs) on a number of
computers sitting on the internet should be carefully designed.
Computers may have different operating systems, hardware and
the programs may be written in different programming
languages.
Unreliable Multicasting
If multicast software fails to transfer a message, part of the
45. message, the receiver gets a corrupted message, or the receiver
gets the same message more than once it is not reliable.
Reliable Multicasting
If multicast does not have the problems explained in the above
paragraph it is reliable. However in a reliable multicast system
the messages may not been received in the same order. A
process sends messages m1 and m2 in the order m1, m2 but the
receiver may get them in m2, m1. Obviously a reliable system
on the other end will put the messages in the right order. The
order of the messages from the sender to the receiver could be
in FIFO (First in, First Out), an unorganized (Casual order) or
automatic. In the automatic order of the messages sent by the
sender won’t change.
6.5 The Java Basic Multicast API
As always let me explain the classes and methods that are
needed for writing a multicast system through programs. But
before explaining the following example I need to let you know:
We cannot use "localhost” or "vulcan.seidenberg.pace.edu". We
need to barrow a multicast address. We need to pick up an
address in the range: 224.0.0.1 to 239.255.255.255. In this
range we have 228 which are 268,435,456 addresses. Pages
189-190.
Note: If you pick an address and you get an error message
saying something like “The address in use” pick a different
address because somebody is using this address.
Example 4: In the following programs the sender sends the
message: Hello All to all the receivers.
How to run the following programs:
46. 1. Make a folder (I named it: Sender) for the sender class as an
eclipse workstation.
2. Make a folder (I named it: Reciver1) for the receiver class as
an eclipse workstation.
3. Copy the folder: Reciever1 several times and rename them
Reciever2, Reciever2, ..
4. Put all of them on the screen narrow the eclipse editors such
that all of them visible.
5. Run all the receivers.
6. Run the sender.
You must see the message: Hello All in all the receivers’
consoles.
import java.net.*;
publicclass Example4Sender{
publicstaticvoid main(String[] args){
try{
InetAddress group = InetAddress.getByName("239.1.2.3");
MulticastSocket s = new MulticastSocket(3456);
s.setTimeToLive(32);
String msg = "Hello All.";
DatagramPacket packet = new DatagramPacket(msg.getBytes(),
msg.length(), group, 3456);
s.send(packet);
s.close();
}
catch (Exception ex){
ex.printStackTrace( );
}
}
47. }
import java.net.*;
publicclass Example4Receiver{
publicstaticvoid main(String[] args){
try{
InetAddress group = InetAddress.getByName("239.1.2.3");
MulticastSocket s = new MulticastSocket(3456);
System.out.println("Joined group at 239.1.2.3 port 3456");
s.joinGroup(group);
byte[] buf = newbyte[100];
DatagramPacket recv = new DatagramPacket(buf, buf.length);
s.receive(recv);
System.out.println(new String(buf));
s.close();
}
catch (Exception ex){
ex.printStackTrace( );
}
}
}
Output:
Hello All
Description:
Example4Sender:
48. · InetAddress group = InetAddress.getByName("239.1.2.3"):
We had this class in the previous chapters.
· MulticastSocket s = new MulticastSocket(3456): We did not
have this class in previous chapters. This a specialized socket
that we can use in a multicast system. Read page 189, number 3
to get more information about this class.
· s.setTimeToLive(32): Sets the default time-to-live for
multicast packets sent out on this MulticastSocket in order to
control the scope of the multicasts. The scope of the multicast is
shown on page 193. The default value is zero.
Other instructions in this class have been explained in the
previous chapters.
Example4Receiver:
· InetAddress group = InetAddress.getByName("239.1.2.3"): Is
creating an address object. The host is: "239.1.2.3". The sender
and all the receivers must have the same host. In this case all of
them belong to the same group.
· MulticastSocket s = new MulticastSocket(3456): A multicast
socket object with the same host as the sender’s port. The
variable: s refers to this socket.
· s.joinGroup(group): It is this instruction that makes the socket
to be a member of the same group (same host).
Note: If in a program we need to remove a member we call the
method: s.leaveGroup(group).
Read example 2 in pages 195-197 and write classes for the
following exercise:
49. Exercise 3: Write three sender/receiver programs such that the
first one sends a message to the second one. The second one
adds a phrase to the message and sends it to the third one.
6.6 Reliable Multicast API
The API that with them we wrote the program in the above
example provides unreliable multicasting. Some of the message
sent by senders may not reach to a desired receiver, However
there are reliable multicast API like JRM and Tom in the market
(read page 197, section 6.6).