For Avatar Only III Continued

profilekpecet
lecture_2.doc

1

Lecture 2

The Socket API Continued

For Chapter 5 & 6 of Distributed Computing: Principles and Applications

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:

image1.png

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.

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.*;

public class MyServer {

public static void 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();

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;

public class MyClient {

public static void 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);

}

}

}

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 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.*;

public class MyServer {

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

try {

final int MAX_LEN = 100;

byte[] buffer = new byte[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);

}

} catch (IOException e) {

System.out.println("Error: " + e);

System.exit(0);

}

}

}

The client:

import java.io.*;

import java.net.*;

import java.util.*;

public class MyClient {

public static void 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();

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.

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:

public class Main {

public static void 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);

t1.start();

t2.start();

try{

t1.join();

t2.join();

}catch(Exception e){

System.out.println("Error: " + e);

System.exit(0);

}

System.out.println((m1.result*m2.result));

}

}

&&&&&&&&&&&&&&&&&&&

public class MyThread implements Runnable{

private int a, b;

public int result;

public MyThread(int a, int b){

this.a = a;

this.b = b;

}

public void 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: 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:

public class 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: public void 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 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.*;

public class MyServer {

public static void 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){

MyThread a = new MyThread(serverSocket.accept());

Thread t = new Thread(a);

t.start();

}

}

}

import java.io.*;

import java.net.*;

public class MyThread implements Runnable{

Socket clientSocket;

public MyThread(Socket clientSocket){

this.clientSocket = clientSocket;

}

public void run(){

try{

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

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

while (true) {

String s = in.readLine();

if (s == null || s.equals("."))

break;

System.out.println("From the client: " + s);

out.println(s);

}

out.close();

in.close();

clientSocket.close();

} catch (IOException e){

System.out.println("Error from the thread: " + e);

}

}

}

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

import java.io.*;

import java.net.Socket;

import java.util.Scanner;

public class MyClient {

public static void 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(".")){

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:

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.

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.

static private synchronized void increment( ){

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.

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 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:

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.*;

public class Example4Sender{

public static void 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( );

}

}

}

import java.net.*;

public class Example4Receiver{

public static void 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 = new byte[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:

· 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:

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).