Solutions Manual: Chapter 22 Big Java, by Cay Horstmann 21

Review Exercises

R22.1

A server is a provider of services. A client is a consumer of services. Usually, multiple clients can connect to a server at one time.

R22.3

The socket throws an UnknownHostExeption if it can not find the host.

R22.5

It uses the address of the computer to which you want to connect.

R22.7

You will use an InputStream obtained from the Socket.

R22.9

Print streams and writers usually buffer their outputs. They will not send the characters in the buffer until the buffer is full. That is why we sometimes needs to flush the output stream or writer in order make sure every character is send to the server.

R22.11

One can use high level APIs such as the URLConnection and HttpURLConnection classes.

R22.13

An URL, or Uniform Resource Locator, is a pointer to an information resource (such as a web page or an image) on the World Wide Web.

One can create a myservice.html file and upload the file to a server such as geocities.com/john28. The URL will be http://geocities.com/john28/myservice.html.

Type the URL, http://geocities.com/john28/myservice.html , into the address window in one's web browser and click GO.

R22.15

In the GET method, the input is appended after the URL, following a ? character. It has a major disadvantage: Many browsers put a limit on the number of bytes permitted in an URL (sometimes just 255 characters).

In the POST method, the input is located after the request header and a blank line. It does not have any limit on the length of input data.

Programming Exercises

P22.1

ExP22_1.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
/**
This program demonstrates how to get the HTTP header information

use a socket to communicate with a web server. Supply the name of

the host and the resource on the command-line, for example

java ExP22_1 java.sun.com index.html

*/

public class ExP22_1

{

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

{

// get command-line arguments

if (args.length != 2)

{

System.out.println("usage: java ExP22_1 host resource");

System.exit(0);

}

String host = args[0];

String resource = args[1];

// open socket

final int HTTP_PORT = 80;

Socket s = new Socket(host, HTTP_PORT);

// get streams

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();

// turn streams into readers and writers

BufferedReader reader = new BufferedReader(

new InputStreamReader(in));

PrintWriter writer = new PrintWriter(out);

// send command

String command = "GET /" + resource + " HTTP/1.0\n\n";

writer.print(command);

writer.flush();

// read server response

boolean done = false;

while (!done)

{

String input = reader.readLine();

//stop when see a blank line

if (input.trim().length() == 0) done = true;

else System.out.println(input);

}

// always close the socket at the end

s.close();

}

}

P22.3

ExP22_3.java

import java.io.BufferedReader;
import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.IOException;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.net.Socket;

import java.net.URLEncoder;

/**

This program posts a query to a United States Postal Service

server that can look up the ZIP code for a city name. It uses

the socket API instead of the URLConnection. Supply the city

name and an optional state on the command line, such as

java ExP22_3 Los Angeles, CA

*/

public class ExP22_3

{

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

{

// get command-line arguments

String input;

if (args.length > 0)

{

input = args[0];

for (int i = 1; i < args.length; i++)

input += " " + args[i];

}

else

input = "90210";

String host = "www.usps.gov";

// open socket

final int HTTP_PORT = 80;

Socket s = new Socket(host, HTTP_PORT);

// get streams

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();

// turn streams into readers and writers

BufferedReader reader = new BufferedReader(

new InputStreamReader(in));

PrintWriter writer = new PrintWriter(out);

// send command

String query = "ctystzip=" + URLEncoder.encode(input) + "\n";

StringBuffer command = new StringBuffer();

command.append("POST /cgi-bin/zip4/ctystzip HTTP/1.1\n");

command.append("Host: www.usps.gov\n");

command.append("Content-type: application/x-www-form-urlencoded\n");

command.append("Content-length: ");

command.append("" + query.length());

command.append("\n\n");

command.append(query);

System.out.println(command);

writer.print(command);

writer.flush();

// read server response

String inputLine;

while ( (inputLine = reader.readLine()) != null)

{

System.out.println(inputLine);

}

// always close the socket at the end

s.close();

}

}

test.htm

<HTML<HEAD<TITLE>USPS City State / ZIP Code Associations</TITLE</HEAD<BODY>
<A HREF="http://www.usps.gov/maps/headnav.map" target="_top"<IMG SRC="http://www.usps.gov/images/headnav.gif" ALT="United States Postal Service" BORDER=0 ISMAP</A<CENTER>

<H2>City State / ZIP Code Associations<BR</H2>

To find the ZIP Code for a mailing address, check out our <A HREF = ../../ncsc/lookups/lookup_zip+4.html>ZIP+4 Code Lookup.</A<BR>

<A HREF = "/ncsc/faq/"target=_top">Questions and Comments</A> | <A HREF = "/ncsc/">Return to ZIP Code Lookup and Address Information</A>

</CENTER>

<HR<p>

<FORM METHOD="POST" ACTION="/cgi-bin/zip4/ctystzip">

<INPUT SIZE="35" MAXLENGTH="35" NAME="ctystzip" value="90210

"> <INPUT TYPE="submit" VALUE="Process">

</FORM>

<PRE>

<b>90210</b> is associated with the following:<p> <p> For this ZIP Code, ZIP Code<br>City Name State the city name is: Type<br>------<BR>BEVERLY HILLS CA ACCEPTABLE (DEFAULT) STANDARD <BR</PRE>

</ul>

</ul>

</b>

<p>

<HR>

<center>

<i>Version 3.2 Database 03/2002<br</i>

<i<FONT SIZE=2>Copyright &#169; 1997 United States Postal Service. All rights reserved.<BR>

Developed by the USPS National Customer Support Center</FONT</i<BR>

</center>

</BODY</HTML>

P22.5

BankAccount.java

/**
A bank account has a balance that can be changed by
deposits and withdrawals.
*/
public class BankAccount
{
/**
Constructs a bank account with a zero balance

*/

public BankAccount()

{

balance = 0;

}

/**

Constructs a bank account with a given balance

@param initialBalance the initial balance

*/

public BankAccount(double initialBalance)

{

balance = initialBalance;

}

/**

Deposits money into the bank account.

@param amount the amount to deposit

*/

public synchronized void deposit(double amount)

{

double newBalance = balance + amount;

balance = newBalance;

}

/**

Withdraws money from the bank account.

@param amount the amount to withdraw

*/

public synchronized void withdraw(double amount)

{

double newBalance = balance - amount;

balance = newBalance;

}

/**

Gets the current balance of the bank account.

@return the current balance

*/

public synchronized double getBalance()

{

return balance;

}

private double balance;

}

Bank.java

/**
A bank consisting of multiple bank accounts.
*/
public class Bank
{
/**
Constructs a bank account with a given number of accounts
@param size the number of accounts
*/
public Bank(int size)
{
accounts = new BankAccount[size];

for (int i = 0; i < accounts.length; i++)

accounts[i] = new BankAccount();

}

/**

Deposits money into a bank account.

@param accountNumber the account number

@param amount the amount to deposit

*/

public void deposit(int accountNumber, double amount)

{

BankAccount account = accounts[accountNumber];

account.deposit(amount);

}

/**

Withdraws money from a bank account.

@param accountNumber the account number

@param amount the amount to withdraw

*/

public void withdraw(int accountNumber, double amount)

{

BankAccount account = accounts[accountNumber];

account.withdraw(amount);

}

/**

Gets the balance of a bank account.

@param accountNumber the account number

@return the account balance

*/

public double getBalance(int accountNumber)

{

BankAccount account = accounts[accountNumber];

return account.getBalance();

}

private BankAccount[] accounts;

}

BankClient.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import java.net.Socket;

/**

This program tests the bank server.

*/

public class BankClient

{

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

{

final int SBAP_PORT = 8888;

Socket s = new Socket("localhost", SBAP_PORT);

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();

BufferedReader reader = new BufferedReader(

new InputStreamReader(in));

PrintWriter writer = new PrintWriter(out);

String command = "DEPOSIT 3 1000\n";

System.out.print("Sending: " + command);

writer.print(command);

writer.flush();

String response = reader.readLine();

System.out.println("Receiving: " + response);

command = "WITHDRAW 3 500\n";

System.out.print("Sending: " + command);

writer.print(command);

writer.flush();

response = reader.readLine();

System.out.println("Receiving: " + response);

command = "QUIT\n";

System.out.print("Sending: " + command);

writer.print(command);

writer.flush();

s.close();

}

}

BankServer.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
A server that executes the Simple Bank Access Protocol.

It can accept simultaneous connections from multiple clients.

*/

public class BankServer

{

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

{

final int ACCOUNTS_LENGTH = 10;

Bank bank = new Bank(ACCOUNTS_LENGTH);

final int SBAP_PORT = 8888;

ServerSocket server = new ServerSocket(SBAP_PORT);

System.out.println("Waiting for clients to connect...");

Socket s;

while (true)

{

s = server.accept();

BankService service = new BankService(s, bank);

service.start();

}

}

}

BankService.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.net.Socket;

import java.util.StringTokenizer;

/**

Executes Simple Bank Access Protocol commands

from a socket.

*/

public class BankService extends Thread

{

/**

Constructs a service object that processes commands

from a socket for a bank.

@param aSocket the socket

@param aBank the bank

*/

public BankService(Socket aSocket, Bank aBank)

{

s = aSocket;

bank = aBank;

}

/**

Executes all commands until the QUIT command or the

end of input.

*/

public void run()

{

try

{

BufferedReader in = new BufferedReader(

new InputStreamReader(s.getInputStream()));

PrintWriter out = new PrintWriter(

s.getOutputStream());

while (true)

{

String line = in.readLine();

System.out.println("Received: " + line);

if (line == null || line.equals("QUIT"))

return;

String response = executeCommand(line);

System.out.println("Sending: " + response);

out.println(response);

out.flush();

}

}

catch (IOException e)

{

System.out.println(e.getMessage());

}

}

/**

Executes a single command.

@param line the command

@return the reply to send to the client.

*/

public String executeCommand(String line)

{

StringTokenizer tokenizer

= new StringTokenizer(line);

String command = tokenizer.nextToken();

int account = Integer.parseInt(tokenizer.nextToken());

if (command.equals("DEPOSIT"))

{

double amount = Double.parseDouble(

tokenizer.nextToken());

bank.deposit(account, amount);

}

else if (command.equals("WITHDRAW"))

{

double amount = Double.parseDouble(

tokenizer.nextToken());

bank.withdraw(account, amount);

}

else if (!command.equals("BALANCE"))

return "Invalid command";

return account + " " + bank.getBalance(account);

}

private Socket s;

private Bank bank;

}

P22.7

Service.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import java.net.Socket;

import java.util.StringTokenizer;

/**

Computes the square root of a number from a socket.

*/

public class Service

{

/**

Constructs a service object that computes the

square root of a number.

@param aSocket the socket

*/

public Service(Socket aSocket)

{

s = aSocket;

}

/**

Computes the square root of a number from a socket.

*/

public void doService() throws IOException

{

BufferedReader in = new BufferedReader(

new InputStreamReader(s.getInputStream()));

PrintWriter out = new PrintWriter(

s.getOutputStream());

String line = in.readLine();

try

{

double response = Math.sqrt(Double.parseDouble(line));

System.out.println("Sending: " + response);

out.println(response);

}

catch (NumberFormatException e)

{

System.out.println("Sending: NaN");

out.println("NaN");

}

out.flush();

}

private Socket s;

}

ExP22_7Client.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;

import java.io.PrintWriter;

import java.net.Socket;

/**

This program tests the square root server.

*/

public class ExP22_7Client

{

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

{

final int PORT = 8888;

Socket s;

while (true)

{

BufferedReader jin = new BufferedReader(

new InputStreamReader(System.in));

String input;

System.out.print("\nPlease enter a number: ");

input = jin.readLine();

s = new Socket("localhost", PORT);

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();

BufferedReader reader = new BufferedReader(

new InputStreamReader(in));

PrintWriter writer = new PrintWriter(out);

String response;

writer.print(input + "\n");

writer.flush();

response = reader.readLine();

System.out.println("The square root of " + input + " is: " + response);

}

}

}

ExP22_7Server.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.lang.Double;

/**

A server that computes the square root of a number.

*/

public class ExP22_7Server

{

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

{

final int PORT = 8888;

ServerSocket server = new ServerSocket(PORT);

System.out.println("Waiting for clients to connect...");

while (true)

{

Socket s = server.accept();

Service service = new Service(s);

service.doService();

s.close();

}

}

}

P22.9

ExP22_9.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;

import java.io.OutputStream;

import java.io.PrintWriter;

import java.net.URL;

import java.net.URLConnection;

import java.net.URLEncoder;

/**

This program shows the protocol, host, port, and file components

of a url using the methods in the URL class.

java ExP22_9 http://www.java.sun.com:80/index.html

*/

public class ExP22_9

{

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

{

String input;

if (args.length == 1)

{

input = args[0];

}

else

input = "http://www.java.sun.com:80/index.html";

URL u = new URL(input);

System.out.println("Protocol: " + u.getProtocol());

System.out.println("Host : " + u.getHost());

System.out.println("Port : " + u.getPort());

System.out.println("File : " + u.getFile());

}

}

P22.11

Chatter.java

/**
A class represent a chat room user.

*/

public class Chatter

{

/**

Constructs a chatter with a name.

*/

public Chatter(String aName)

{

name = aName;

}

/**

Returns the name

@return the name

*/

public String getName()

{

return name;

}

String name;

}

ChatRoom.java

import java.util.HashMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.ListIterator;
import java.io.PrintWriter;

/**

A chat room consisting of multiple chatters.

*/

public class ChatRoom

{

/**

Constructs a chat room with a given number of capacity.

@param aCapacity the capacity of the room

*/

public ChatRoom(int aCapacity)

{

capacity = aCapacity;

chatterHash = new HashMap(capacity);

activeService = new ArrayList(capacity);

}

/**

Register a chatter to the room.

@param aName the name to register

*/

public void register(String aName)

{

chatterHash.put(aName, new Chatter(aName));

}

/**

De-register a chatter to the room.

@param aName the name to de-register

*/

public void leave(String aName)

{

chatterHash.remove(aName);

}

public void add(ChatService cs)

{

activeService.add(cs);

}

/**

Broadcast a message to everyone in the room.

@param msg the message to be broadcast

@param out the place to write the message

*/

public void broadcast(String requestor, String msg, ChatService chatService)

{

ListIterator li = activeService.listIterator();

while (li.hasNext())

{

ChatService cs = (ChatService) li.next();

if (cs != chatService & cs.getUserName() != null)

{

cs.putMessage(requestor + ": " + msg);

}

}

}

private ArrayList activeService;

int capacity;

private HashMap chatterHash;

}

ChatClient.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;