0% found this document useful (0 votes)
151 views23 pages

Program-To-Program Communications Over IP: - Classes Supporting TCP/IP Based Client-Server Connections

The document discusses program-to-program communications over IP networks using ports and sockets. It explains concepts like IP addresses, ports, UDP, TCP, clients, servers and how they interact and establish connections to transfer data over the internet.

Uploaded by

Tumus Tony
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
151 views23 pages

Program-To-Program Communications Over IP: - Classes Supporting TCP/IP Based Client-Server Connections

The document discusses program-to-program communications over IP networks using ports and sockets. It explains concepts like IP addresses, ports, UDP, TCP, clients, servers and how they interact and establish connections to transfer data over the internet.

Uploaded by

Tumus Tony
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

nabg nabg

java.net.*;
Classes supporting TCP/IP based client-server

import java.net.*; connections.

(You will meet TCP/IP from C/C++ perspective in CSCI214;


inner workings of TCP/IP covered in many SECTE subjects)
In days of Java and the Internet, the and the Internet
component had introductory coverage of TCP/IP.

You must have had something on TCP/IP in CSCI102; it cannot be that the only coverage of networking is in elective subjects.

nabg nabg

Program-to-program
IP (Internet Protocol)
communications over IP
Each machine has one (or more) IP addresses How to identify end-point program?
IP protocol defines how to get data packets across Port
Portal, a door or gateway
the Internet from one machine to another.
Ports are OS structures
But need Data buffer for input/data buffer for output
Client program communicates with server program Identified by a number
Not client machine communicates with server machine Programs ask OS for use of a port
Other protocols layered over IP allow program to Server program asks for specific port number, publishes its
program communications port number; client program uses this to identify server
OS allocates port number for client
TCP & UDP

nabg nabg

UDP & TCP Ports & sockets


UDP
Client composes one data request packet
Ports belong to OS
Client sends it to server (identified by combination of IP address and Programs need access to the I/O buffers on
port number; includes its own IP address and port number in packet
header)
Server responds with one packet (using client address from header)
port
Connection terminated Sockets
TCP
TCP uses IP and ports in same way as UDP I/O streams working with buffers of given port
TCP libraries hide packet nature of communications
Client and server see connection as continuously open input-output
stream, both can read and write data
TCP library code deals with all the hard bits of arranging for data
transmission in packets, guaranteed delivery, flow-control etc
nabg nabg

Sockets
clients and servers
network (Internet or intranet)
Actually two kinds
Data stream sockets
Read and write application data
Server sockets Client Server
Used when client wants to make connection to
server
Java Applet in Web page Java server
Client details put in server-socket input buffer
Additional I/O buffers allocated for data transfers with this Java application C++ server
client C++ or other application
Server program given all these details
No need for client and server to be implemented in same
language they can often communicate by text messages.

nabg nabg

Clients and Servers Clients


Code for handling client side is completely standard, the
Java Applets are restricted to servers running on same machine as Webserver program that code examples in books on TCP/IP programming in C/C++
provided HTML page with Applet
can easily be adapted for Java.
Server program must be running (listening at well known port)
client
official servers (like ftpd, httpd, ...) are organised by OS on server machine
build address structure for server
local standards are also handled automatically via inetd system (system
administrator defines list of extra server programs run at this site and their ports, if get socket
OS receives request at port it starts corresponding server program; connect to server
on Windows, programs are registered with OS as services and get started while not finished
automatically)
get command from user
private server programs must be launched by owner
write to socket
Obviously, this could (& should) be
read reply handled by a dedicated thread if
Client program launched by user show reply to user you also want to maintain GUI
Familiar examples browser client, ftp-client interaction

nabg nabg

Servers Servers
The normal server (as described in TCP/IP texts) is a
Server may have to deal with many clients forking server:
Concurrency strategies:
Serial:
deal with clients one at a time, handling all requests until client server (listener) Different processes!
disconnects; then start handling next client. create socket
OS helps by maintaining a queue of clients who wish to server (child process)
bind to well known port
connect; forever()
listen (i.e. activate service) read next request
Forking forever() if bye then quit
Start a new process for each client just as was described for handle request
accept client
WebServer (this strategy rarely used with Java servers)
fork subprocess to deal with client send response
Threaded
Each client gets a thread to serve them new socket created by
accept is passed to child
nabg nabg

Threaded server
Servers All the one process (independent clients)

main thread handle_client


Forking server traditionally favoured on Unix systems forever()
create socket
read next request
lots of system support bind to port if bye then break
relatively easy to program activate handle request
forever() send response handle_client

appropriate when clients are independent (dont desire to thread die


forever()
read next request
accept client if bye then break
interact) handle request
send response
create new thread to handle_client thread die

deal with this client forever()


Alternative start thread in
read next request
if bye then break handle_client
handle_client handle request
forever()
a server that supports multiple concurrent clients, send response
read next request
if bye then break
usually via a threads mechanism thread die handle request
send response
thread die

nabg nabg

Threaded server Servers


All the one process (interacting clients)

main thread handle_client shared Java servers are rarely (if ever) forking servers
forever() data though can launch a process via Runtime object
create socket
read next request
bind to port if bye then break
Javas support for threads makes it simpler than
activate handle request usual to implement as threaded server
forever() send response handle_client
forever() all objects have associated locks, simply need to start to
accept client thread die read next request
if bye then break
handle request
send response
use these (facilitating safe use of shared data)
create new thread to handle_client thread die
thread package provides simple subset with most useful
deal with this client forever()
read next request features from a full threads implementation
start thread in if bye then break handle_client
handle_client handle request
forever() ...
read next request
send response if bye then break Java solution: have a ClientHandler class (optionally inherits Thread),
thread die handle request
send response create an instance for each client (passing new socket), let it run()
thread die

nabg nabg

Your programming of
Server provides a service
Client - server systems
You can rely on the libraries to handle: Typically, a server is a bit like an instance of a
establishment of communications link
class that has a public interface advertising a few
reliable data exchange (TCP/IP) (or the rarely useful simple
operations it can perform for a client.
packet transfer based on cheaper UDP/IP mechanisms) Example 1: HTTP server
GET, POST, OPTIONS,
What you really see at both ends is a connection
Example 2: FTP server
that supports read and write access. List directory, change directory, get file, put file,
You must invent Sometimes will have a service with only one
Application
specific operation echo, ping,
Client Application Server Application
PROTOCOL
nabg nabg

Client server application Your programming of


protocol Client - server systems
Each operation defined by server has name, and Decide on the different commands and data that you
arguments and returns particular kind of data (or want to exchange. List for each command (request) :
an exception) data that may be sent with the command
Client must supply data identifying operation allowed responses (success, failure, other eg defer)
required, and supply and data needed. and note appropriate action
Protocol specifies how client to supply such data that may come with different responses
information and what kinds of responses it may Associate suitable key words with each command,
receive and key word (or numeric codes) that could identify
possible responses.

nabg nabg

Your programming of
Your programming of
Client - server systems
Client - server systems
Client (things that you should think about)
how does user select the server? Server
connection mechanism set up; how to handle failures? First, what strategy?
how does user select the commands to be sent, and how are Depends on load that you expect on your server, if
necessary input data obtained? lightly used a serial server may suffice (and is a lot
sending data; easier to implement)
getting response
switch(response code) into ... If expect to deal with many clients, then need
handle various permitted responses appropriate for last request concurrent (threaded) server
displaying response; Much of code is standardized, so can cut-copy-paste
how does user terminate session?

nabg nabg

Your programming of Your programming of


Client - server systems Client - server systems
Server (things that you should think about) Handle-client
setting up listener mechanism, accepting new client and getting socket,
creating thread for new client these aspects should all be standard If serial server architecture,
handle_client call a function that will accept commands and
reading request; dealing with the unexpected, excessive data, ... generate responses until user disconnects
switch(keyword) into ... If threaded architecture
invoke separate functions for each of the commands that this create a runnable ClientHandler object
server handles
create a thread that runs this ClientHandler
generation of response let multiple clients run with own threads
how does it terminate?
nabg nabg

Java support for networking network classes


Socket
java.net package includes a variety of classes that are client side connection to network
essentially wrappers for the simple to use but rather
connect(...)
messy Berkeley sockets networking facilities.
provides InputStream and OutputStream (byte
classes for the sockets oriented; re-package inside a DataInputStream etc)
classes that represent network addresses for server machines status info ...
(hosts) and clients
classes that handle URLs ServerSocket
class for talking http protocol to httpd server on some host server side connection to network
...
accept(...) (gives back new Socket for use in handle_client())
status info, ...

nabg nabg

network classes Example


Program
InetAddress
takes hostname and port number as command line arguments
data structure representing an address (a final class, basically its
an opaque box holding system dependent information needed by Socket attempts to build InetAddress for host
classes)
attempts to open Socket to host/port combination
create instances using static member functions of class
static InetAddress.getByName(String host) ... creates DataStream adaptors for Socket
can ask for an Internet address for host (specified in dotted decimal or
domain name form) loop
static InetAddress.getLocalHost() (own address) read line of input
if Quit then stop
not really needed as can create Sockets without needing InetAddress send line (and \n!) to server
structures, but can be useful as functions that create InetAddress objects
can return more informative exceptions if something wrong (whereas read bytes returned
exception with Socket simply tells you connection wasnt possible) convert to String and display

A crude substitute for telnet (port 23) talk to echo, etc.

nabg nabg

Example telnet client Basic structure ...


Client reads in a line, making it a Java String with Essentially as shown before ...
16-bit characters
telnet (or other standard service) expects ASCII client
text for communications build address structure for server
get socket - connect to server (one step process with Java classes)
Client cannot simply write the String to socket
while not finished
(which it could if talking Java-to-Java)
get command from user
Instead must write as 8-bit characters write to socket
Can use DataInputStream and read reply
DataOutputStream to handle this show reply to user
nabg nabg
import java.net.*; Telnet client public static void main(String argv[])
import java.io.*; substitute {
public class NetConnect {
if(argv.length != 2) {
public static void main(String argv[]) System.out.println("Invoke with hostname and port number arguments");
{ check input arguments System.exit(0);
try to use first as a hostname when creating an InetAddress }
try to use second as a port number InetAddress ina = null;
create socket for InetAddres, port combination try { ina = InetAddress.getByName(argv[0]); }
create streams for socket catch(UnknownHostException uhne) {
promote System .in to BufferedReader System.out.println("Couldn't interpret first argument as host name");
System.exit(0);
loop
}
prompt for input; read line, trim,
int port = 0;
if Quit then break
try { String ps = argv[1].trim(); port = Integer.parseInt(ps); }
write as bytes to socket
catch (NumberFormatException nfe) {
loop reading bytes (until get \n)
System.out.println("Couldn't interpret second argument as port number");
print data read
System.exit(0);
}
}
}

nabg nabg

public static void main(String argv[]) public static void main(String argv[])
{ ... { ...
Socket s = null; BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
try { s = new Socket(ina, port); } byte[] inputbuffer = new byte[2048];
catch (IOException io) { for(;;) {
System.out.println("No luck with that combination; try another host/port"); System.out.print(">");
System.exit(0); String str = null;
} try { str = d.readLine(); }
DataOutputStream writeToSocket = null; catch (IOException io) {System.exit(0); }
DataInputStream readFromSocket = null; str = str.trim();
try { if(str.equals("Quit")) break;
writeToSocket = new DataOutputStream(s.getOutputStream()); try { writeToSocket.writeBytes(str + "\n"); }
readFromSocket = new DataInputStream(s.getInputStream()); catch (IOException io) {
} System.out.println("Write to socket failed"); System.exit(0);
catch (IOException io) { }
System.out.println("Got socket, but couldn't set up read/write communications");
System.exit(0);
}

nabg nabg

public static void main(String argv[])


{ ...
for(;;) {
...
Reading and writing @ sockets
int numread = 0;
for(numread=0;;numread++) { If talking Java to Java, it is your choice
byte b = 0; promote socket connections to BufferedReader & BufferedWriter (send
try { b = readFromSocket.readByte(); Unicode characters across network)
inputbuffer[numread] = b; } promote socket connections to ObjectInputStream and ObjectOutputStream
catch (IOException io) { (send objects across the network this is often the best)
System.out.println("Read from socket failed"); System.exit(0); promote socket connections to DataInputStream and DataOutputStream,
} send Java doubles, UTF-8 data etc across web
if(b == '\n') break; If talking Java to other
} promote socket connections to DataInputStream and DataOutputStream,
String response = new String(inputbuffer, 0, numread); send data as text, writing and reading using byte transfers (dont want to
System.out.println(response); confuse other programs with Unicode!)
} could have simply printed data from buffer
} but more typically would want String
nabg nabg

Examples reads and writes Example simple client


This client meant for general use, not Java-to-Java, This simple client works, eg connect to port 7 of
so use DataInputStream, DataOutputStream, and typical Unix server and you are talking to echo
text written and read as bytes. program
Most telnet like services are line-oriented each line you enter will be echoed by other
read one line up to and including \n machine
respond with single line (if multi-line response, then
some agreed terminator, eg line with just .)
Hence code to make sure \n sent and loop
reading characters until get \n (could have used
DataInputStream.readLine() but it is deprecated)

nabg nabg

Examples
Simple serial server
Examples getDate etc
Threaded version of same
Internet Relay Chat program

nabg nabg

NetBeans and examples


NetBeans environment helps develop and test
single program, Remote service
Now have client and server
(simple serial server)
If developing in NetBeans
Use separate projects (possibly sharing files)
Build client, build server; get .jar files with applications
Run at cmd.exe level so can start server application
then start client application from separate cmd.exe shell
nabg nabg

Service operations Protocol


getDate Easy!
returns date getDate
client sends string Date
getFortune client receives string with Date-time on server
returns a random fortune cookie string chosen getFortune
from a small collection client sends string Fortune
client receives string chosen from servers collection
quit quit
client politely says goodbye client sends string Quit
server does not respond, it just closes socket

nabg nabg

Communications Serial server


In this example, use ObjectStreams Set up server socket
overkill! Loop forever
wait for client to connect (blocking accept call)
good practice for real examples get socket connecting to client
open streams for socket
loop
read command
if command was getDate send back date-time
ObjectStreams preferred approach for Java to Java else if command was getFortune send back fortune
until command was quit
close client socket

nabg nabg

public static void main(String[] args)


{
Client code if(args.length != 2) { Basic setup get host & port
System.out.println(
"Invoke with hostname and port number arguments");
import java.net.*; System.exit(1);
import java.io.*; }
String hostName = args[0];
public class Client int port = 0;
{ try {
public static void main(String[] args) String ps = args[1].trim();
{ port = Integer.parseInt(ps);
// Procedural client, just one mainline for }
// something this simple! catch (NumberFormatException nfe) {

System.out.println(
}
"Couldn't interpret second argument as port number");
System.exit(1);
}
}
nabg nabg

public static void main(String[] args) // Get I/O streams, make the ObjectStreams
{ // for serializable objects
ObjectInputStream responseStream = null;

ObjectOutputStream requestStream = null;
// Create client socket try {
Socket sock = null; requestStream = new ObjectOutputStream(
try { sock.getOutputStream());
sock = new Socket(hostName, port); requestStream.flush();
responseStream = new ObjectInputStream(
}
sock.getInputStream());
catch(Exception e) { }
// I/O, unknown host, ... catch(IOException ioe1) {
System.out.println("Failed to connect because " System.out.println("Failed to get socket streams");
System.exit(1);
+ e.getMessage());
}
System.exit(1); System.out.println("Connected!");
}

Output first, flush it, then input else system may stall; feature!

nabg nabg

// main loop, user commands line = input.readLine();


BufferedReader input = new BufferedReader( if(line==null) { System.exit(0); }
new InputStreamReader(System.in)); if(line.equals("Fortune")) {
for(;;) { requestStream.writeObject(line);
System.out.print(">"); requestStream.flush();
String line; requestStream.reset();
try { String cookie = (String) responseStream.readObject();
// see next two slides System.out.println(cookie);
} }
catch(IOException ioe2) { else
System.out.println("Problems!"); if(line.equals("Date")) {
System.out.println(ioe2.getMessage()); requestStream.writeObject(line);
System.exit(1); requestStream.flush();
} requestStream.reset();
catch(ClassNotFoundException cnfe) { String date = (String) responseStream.readObject();
System.out.println("Got something strange back from System.out.println(date);
server causing class not found exception!"); }
System.exit(1); else
}
}

nabg nabg


else
if(line.equals(Quit)) {
Sending and receiving
// Disconnect, dont expect response to Quit
requestStream.writeObject(line); Write the object
requestStream.flush();
Flush
requestStream.reset();
requestStream.close();
OS may not send small message!
It waits assuming that there will be more to send and better to
responseStream.close(); send one big package than two small ones
break;
So force sending
}
// ignore any other input commands
Reset
// they are invalid Remember those dictionaries associated with
objectstreams that remember every object written or
read?
Clear by explicitly resetting
A reset by the sender causes a reset on receiver
nabg nabg

ObjectStream & Strings


Strings are objects!
Class String implements Serializable Simple serial server
Can use Strings with ObjectInputStream
and ObjectOutputStream

nabg nabg

Usual structure Chosen port number?


Create server socket bound to chosen port and Dont use numbers < 1024 ever (unless your program
prepare to accept client connections would be started by root on Unix i.e. it is some major server like
httpd, ftpd, )
Loop
blocking wait for client to connect Avoid numbers < 10,000
get new datastream socket when client does connect 1K5K many claimed by things like Oracle
invoke handle client function to process requests 5K10K used for things like X-terminals on Unix
close datastream socket when client leaves 10K..65000 ok usually
Some ports will be claimed, e.g. DB2 will grab 50,000
If request to get port at specified number fails, pick a different
number!

nabg nabg

import java.io.*; public static void main(String[] args) {


import java.net.*; int port = DEFAULT_PORT;
import java.util.*; if(args.length==1) {
public class Server try { port = Integer.parseInt(args[0]); }
{ catch (NumberFormatException ne) { }
private static final int DEFAULT_PORT = 54321; }
private static Random rgen = ServerSocket reception_socket = null;
new Random(System.currentTimeMillis()); try {
private static String getFortune() { } reception_socket = new ServerSocket(port);
private static void handleClient(Socket sock) { }
public static void main(String[] args)
}
{ catch(IOException ioe1) { }
int port = DEFAULT_PORT; for(;;) {
if(args.length==1) { Socket client_socket=null;
try { port = Integer.parseInt(args[0]); } try {
catch (NumberFormatException ne) { }
} client_socket =
ServerSocket reception_socket = null; reception_socket.accept();
try { }
reception_socket = new ServerSocket(port); catch(IOException oops) { }
}
catch(IOException ioe1) { } handleClient(client_socket);
for(;;) { } }
} } Simple serial server!
} }
nabg nabg

for(;;) {
try {
private static void handleClient(Socket sock) { String request = (String) requests.readObject();
ObjectInputStream requests = null; if(request.equals("Date")) {
ObjectOutputStream responses = null; responses.writeObject((new Date()).toString());
try { responses.flush();
responses = new ObjectOutputStream( responses.reset();
}
sock.getOutputStream());
else
responses.flush(); if(request.equals("Fortune")) {
requests = new ObjectInputStream( responses.writeObject(getFortune());
sock.getInputStream()); responses.flush();
} responses.reset();
catch(IOException ioe1) { }
System.out.println("Couldn't open streams"); else
try { sock.close(); } catch(Exception e) {} if(request.equals("Quit")) {
try { sock.close(); } catch(Exception e) {}
return;
break;
} }
for(;;) { }
catch(Exception e) {
} try { sock.close(); } catch(Exception eclose) {}
} return;
}
Setting up of communications streams for current client }
Dispatching remote requests to service functions
}

nabg nabg

Server
private static String getFortune() {
String[] cookies = {

"The trouble with some women is they get all excited about nothing, and then they marry him.",
"It's true hard work never killed anybody, but I figure, why take the chance?",
"A successful man is one who makes more money than his wife can spend.",
"When a man brings his wife flowers for no reason, there's a reason.",
"Genius is the ability to reduce the complicated to the simple."
};

int which = rgen.nextInt(cookies.length);


return cookies[which];
}

Client

nabg nabg

Multiple machines
If practical, run client and server on
different machines What about errors on server side?
Copy client .jar file to second machine
Start server on one machine (with known IP
address or known DNS name)
Start client on second machine
Command line arguments are server DNS name (or
IP address) and port
nabg nabg

and the communications


Errors
First server was fault free nothing can go wrong Client now sending a composite message
except for a break in communications. control (keyword string identifying command)
other data (some form of serializable data, or maybe null
Usually client submits data as well as request if command doesnt take data)
identifier and submitted data may cause
problems on server. Worth introducing a Message structure for client to
send data
Modify our service to illustrate this public class Message implements Serializable {
getFortune(String choice) public String control;
public Serializable associateddata;
client specifies which fortune by supplying a string public Message(String cntrl, Serializable data)
string should represent integer {
integer should be in range control = cntrl;
Bad data results in server side error that must be associateddata = data;
}
returned to client }

nabg nabg

Server needs mechanism to


Using messages first
return errors to client
Client modify code in command loop
At least two approaches: line = input.readLine();
Use the same message structure if(line==null) { System.exit(0); }
control word indicates success or failure if(line.equals("Fortune")) {
System.out.print("Which one : ");
associated data is the response or supplementary information
String choice = input.readLine();
about the failure
requestStream.writeObject(new Message(line, choice));
Create an Exception Object on the server requestStream.flush();
do not throw it on the server! requestStream.reset();
send it back (Exceptions are serializable and go through object Message response = (Message)
responseStream.readObject();
streams)
if(response.control.equals("OK"))
client receives object, determines whether or not is exception System.out.println(response.associateddata);
else
System.out.println(response.associateddata);
}

nabg nabg
Message request = (Message) requests.readObject();
if(request.control.equals("Fortune")) {
int choice;
Server try {
choice = Integer.parseInt(
(String) request.associateddata);
String fortune = getFortune(choice);
Fortune function responses.writeObject(new Message("OK", fortune));
private static String getFortune(int choice) responses.flush(); responses.reset();
{ }
String[] cookies = { catch(NumberFormatException nfe) {
responses.writeObject(new Message("Error" ,
"It's true hard work never killed anybody, but I ", "- non numeric data for choice"));
responses.flush(); responses.reset();
}
};
catch(IndexOutOfBoundsException ndxe) {
return cookies[choice];
responses.writeObject(new Message("Error",
}
"IndexOutOfBounds!"));
responses.flush(); responses.reset();
}
}
nabg nabg

Other version with exceptions Client


if(line.equals("Fortune")) {
Client still sends its requests using those Message System.out.print("Which one : ");
structs String choice = input.readLine();
Response object is what? requestStream.writeObject(new Message(line, choice));
requestStream.flush();
Know it will be a Serializable, but what? requestStream.reset();
String Serializable response =
print it (Serializable) responseStream.readObject();
Exception if(response instanceof Exception)
throw it throw ((Exception) response);
System.out.println(response); // know it is a string
Use instanceof to find if response object is }
Exception

nabg nabg

Server
Client exception handling if(request.control.equals("Fortune")) {
int choice;
try {
catch(IOException ioe2) {
System.out.println("Problems!");
choice = Integer.parseInt(
System.out.println(ioe2.getMessage()); (String) request.associateddata);
System.exit(1); String fortune = getFortune(choice);
} responses.writeObject(fortune);
catch(ClassNotFoundException cnfe) { responses.flush(); responses.reset();
System.out.println("Got something strange back from server }
causing class not found exception!");
catch(NumberFormatException nfe) {
System.exit(1);
} responses.writeObject(nfe);
catch(Exception other) { responses.flush(); responses.reset();
System.out.println( }
"Server probably returned this exception!"); catch(IndexOutOfBoundsException ndxe) {
System.out.println(other); responses.writeObject(ndxe);
} responses.flush(); responses.reset();
}
}

nabg nabg

Concurrent server
No change to client
Threaded version? Server:
! Use application specific client handler class that
implements Runnable
its public void run() method has the code from the
handle_client function (plus any auxiliary functions)
After accepting client
Create new ClientHandler with reference to Socket
Create thread
Thread runs handler
nabg nabg

Add another operation to demonstrate


that each client has separate handler!
Client Ping code
if(line.equals("Ping")) {
Ping requestStream.writeObject(
Client sends Ping as message new Message(line, null));
requestStream.flush();
Server (ClientHandler) responds with requestStream.reset();
Pong plus a count String response =
(String) responseStream.readObject();
count value is incremented each time
System.out.println(response);
count is instance variable of ClientHandler so }
each client has distinct count value

nabg nabg

Server Java 1.5 addition


public class Server
{ Example code creates a new thread for each client
private static final int DEFAULT_PORT = 54321;
public static void main(String[] args)
and destroys the thread when finished.
{ Costly.
Well threads arent as costly as separate processes
for(;;) {
but they arent cheap either.
try {
Socket client_socket = The Java 1.5 concurrency utilities package has
reception_socket.accept(); things like
ClientHandler ch = Executor.newFixedThreadPool
new ClientHandler(client_socket); (which gives you a pool of threads);
Thread t = new Thread(ch); then give Runnable to this pool, a thread will be
t.start();
}
allocated.

nabg nabg

ClientHandler ClientHandler.run()
public class ClientHandler implements Runnable Message request = (Message) requests.readObject();
{ if(request.control.equals("Date")) { }
private int count; else
private ObjectInputStream requests; if(request.control.equals("Fortune")) { }
private ObjectOutputStream responses;
else
private String getFortune(int choice) { }
if(request.control.equals("Ping")) {
public ClientHandler(Socket sock) {
responses.writeObject("Pong " + Integer.toString(++count));
// initialize, open streams etc
responses.flush();
} responses.reset();
public void run() }
{ else
for(;;) { } if(request.control.equals("Quit")) { }
}
}
nabg nabg

Micro
I RC nternet elay hat

nabg nabg

IRC? IRC
Internet relay chat: Client program
host machine runs server program connect to server
program supports multiple concurrent clients (via threading or specify hostname and port and nickname
polling mechanisms) accessing shared data
view channels, submit selection
server program provides
virtual channels
view list of participants, get display of recent messages
each channel related to a discussion topic own messages broadcast to other participants
when first connect to server, can review choices, and pick channel see any messages entered by others
discussion groups on channels
associated with each channel have
group of clients (identified by nicknames)
buffer containing last few messages exchanged

nabg nabg

Micro-IRC Canvas
allows text to scroll up like an ordinary
Misses out the channels layer. computer terminal
List of
MicroIRC server participants
multithreaded Java application
buffer for 10 recent messages
MicroIRC client Sender names, and messages
also multithreaded (listening for messages from others,
responding to local users keys/mouse actions)
List display of names of paticipants
Canvas (fake scrolling) of recent text (no local buffer)
TextField and action Button for message entry Button
TextField (edit your message)
(broadcast message)
nabg nabg

MicoIRC
NetBeans style
Three projects
Server application
Client application
Utilities library

(In /share/cs-pub/csci213 as
compressed collection of
NetBeans projects)

nabg nabg

Structure Overall operation


Server Server started
Threaded (using thread pool) Client connects
ClientHandlers created for each client Client attempts to register
Provides nickname; registration attempt will fail if
SharedData keeps track of connected clients and last nickname already in use
few messages posted If registration succeeds, client receives in return a set of
Client strings with nicknames for all connected clients and a
copy of the last few messages posted.
Simple GUI with text field to post data
Client can now post messages
Separate client thread to handle asynchronous messages Messages posted to the server are distributed to all
from server connected clients

nabg nabg

Distribution of postings by server Communications


Two possible strategies
Thread in ClientHandler that receives message is used
to run code that forwards it to each client
TCP/IP socket streams wrapped in
Separate thread on server ObjectInputStream and ObjectOutputStream
Forever
Sleep a bit
Check if any new messages in buffer
Post each one to each of clients
Serializable objects written and read
This implementation uses first strategy
nabg nabg

Classes - utilities Classes - server


Utilities library Server, the usual
Just a collection of little serializable structs Server procedural main-line, cut-&-paste
A posting has an author and a message code from any other threaded server
The initial data received by a client should contain a ClientHandler
String[] and an array of postings A Runnable
A message has an operation and some other data
SharedData
A MyException is a specialization of Exception
Owns collections of client handlers and recent
postings

nabg nabg

Classes - client Client


ClientProgram procedural, deal with AWT thread Created thread in
command line arguments, create client Handle input fields Client.run()
Used for actionPerformed that
object (which creates its GUI) handles send button Forever
Writes to ObjectOuputStream Blocking read on
Client ObjectInputStream
Read a Message object
Runnable Add_Client
ClientGUI Remove_Client
Post

nabg nabg

public class Message implements Serializable {


public String operation;
Library project public Serializable otherdata;
public Message(String op, Serializable data) {
operation = op;
otherdata = data;
Classes like Posting used in both Client and Server
}
applications }
Create a Java library project (IRCUtilities) public class Posting implements Serializable {
Define the classes public String author;
public String comment;
Build the project public Posting(String person, String txt) {
author = person;
Create Client and Server Application projects comment = txt;
In Library tab of project }
Add library/Project/IRCUtilities }

otherdata in Message will be a Posting or an InitialData object


nabg nabg

public class InitialData implements Serializable {


public String[] playerNames;
Micro-IRC
public Posting[] postings;
public InitialData(String[] names, Posting[] posts) {
Application protocol
playerNames = names;
postings = posts;
Client initiated exchanges
}
} Register
client sends Message with Register and a nickname
server sends either
public class MyException extends Exception {
Message with OK and an InitialData object with details of all
public MyException(String reason) { current players
super(reason); MyException
}
} if client gets OK, then continue; else terminate

determine (main aspects of) application protocol

nabg nabg

Micro-IRC Micro-IRC
Application protocol Application protocol
Client initiated exchanges Server initiated
Post Post
client sends Message with Post and contents of text input server sends Message Post together with a Posting object
buffer containing the nickname of participant who posted message
not acknowledged and contents of message
Quit no acknowledgement from client
client sends Quit: (not acknowledged) Add_Client:
another client has connected
Remove_Client:
some other client has disconnected

determine (main aspects of) application protocol determine (main aspects of) application protocol

nabg nabg

MicroIRC Client MicroIRC Client

Selection of server and establishment of Most messages from server are asynchronous!
connection server sends client a Post whenever any of users on
use command line arguments system has entered data, and sends add/remove
host_name, port number, nickname to use when connect client as others connect and disconnect
construct InetAddress with given host_name, if fail so not synchronized with actions of local user
print error report and quit
implication => Need a separate thread ready at all
socket connection opened to server, again failures
times to handle asynchronous message from server
result in program exiting.

decide on general mechanisms for client,


(but not their implementation)
nabg nabg

MicroIRC Client
displaying response Canvas
allows text to scroll up like an ordinary
several possible ways of handling messages computer terminal
TextArea (disabled) in scrolling window List of
allows user to scroll back, refresh is possible after display participants
temporarily obscured
potentially large storage demands as add Strings to TextArea
array of Strings displayed in window Sender names, and messages
discard oldest if array full
limits storage, still allows some scrollback and refresh
no storage of data
messages drawn directly on Canvas
This option copyarea used to produce scrolling effect
picked for
demo cant view messages scrolled off screen, cant refresh if display
Button
TextField (edit your message)
temporarily obscured (broadcast message)

nabg nabg

public class ClientProgram {


public static void main(String[] args) {
Client GUI if(args.length != 3) { }
InetAddress ina = null;
try { ina = InetAddress.getByName(args[0]); }
Frame with BorderLayout catch(UnknownHostException uhne) { }
int port = 0;
try { String ps = args[1].trim(); port = Integer.parseInt(ps);
java.awt.List
} catch (NumberFormatException nfe) { }
in East area;
Displays its
collection of Client cl = new Client(args[2]);
strings try { Thread.sleep(100); } catch(InterruptedException ie) {}
Create client & GUI
if(!cl.connect(ina, port)) { } (pause to let AWT thread start)
cl.register();
Thread t = new Thread(cl);
Connect
t.start(); Send registration request
} Start thread for asynchronous
} messages
Panel in South, flowlayout, holds label, textfield, actionbutton

nabg nabg

public class ClientGUI extends Frame { public ClientGUI(Client cl) {


public ClientGUI(Client cl) { super("Micro-IRC for " + cl.getName());
// Next slide setLayout(new BorderLayout());
} fMembers=new List(5); fMembers.setEnabled(false);
public void addToList(String s) { fMembers.add(s); } add(fMembers,"East");
public void removeFromList(String s) { fMembers.remove(s); } fCanvas = new Canvas(); fCanvas.setSize(500,400);
fFont = new Font("Serif", Font.PLAIN, 12);
public void addPosting(Posting p) { fCanvas.setFont(fFont); add(fCanvas,"Center");
// later slide Panel p = new Panel();
} p.add(new Label("Your message :"));
fInput = new TextField(" ", 60); p.add(fInput);
String getInput() { return fInput.getText(); } Button b = new Button("Send"); p.add(b);
private List fMembers; b.addActionListener(cl);
private Canvas fCanvas; add(p, "South");
private TextField fInput; pack();
private Button fAction; addWindowListener(cl);
private Font fFont; }
}

ClientGUI ClientGUI
nabg nabg

public void addPosting(Posting p) {


Graphics g = fCanvas.getGraphics();
GUI building FontMetrics f = g.getFontMetrics(fFont); Scroll up
int delta = f.getHeight();
Dimension d = fCanvas.getSize();
The usual g.copyArea(0, delta, d.width, d.height-delta, 0, -delta);
Frame (container) g.clearRect(0, d.height-delta, d.width,delta);
Layout manager defined
Components added g.setColor(Color.red); Add new
List g.drawString(p.author, 4, d.height - f.getDescent());
Canvas
Panel
int pos = 4 + f.stringWidth(p.author) + 10;
Label if(pos<50) pos = 50;
TextField g.setColor(Color.black);
Button
g.drawString(p.comment, pos, d.height - f.getDescent());
ActionListener, WindowListener }

(As data only written to screen, information is lost if window is hidden then re-exposed)
ClientGUI

nabg nabg

public class Client implements Runnable, ActionListener, WindowListener {


public Client(String nickname) { }
Client public void register() { }
public String getName() { return fName; }
boolean connect(InetAddress ina, int port) { }
public void run() { }
Client Runnable, ActionListener, public void actionPerformed(ActionEvent e) { }
public void windowOpened(WindowEvent e) { }
WindowListener public void windowClosing(WindowEvent e) { }
Runnable for separate thread that gets asynchronous public void windowClosed(WindowEvent e) { }
messages from server public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) { }
ActionListener when GUIs button clicked, grab input public void windowActivated(WindowEvent e) { }
from textfield and post it to server public void windowDeactivated(WindowEvent e) { }
WindowListener on window closing, hide GUI, stop private Socket mySocket;
run thread, send quit message to server private ObjectInputStream in;
private ObjectOutputStream out;
private ClientGUI myGUI;
private String fName;
private Thread runThread;
} Client

nabg nabg

public Client(String nickname) { public void register() {


fName = nickname; try {
myGUI = new ClientGUI(this); Message m = new Message("Register", fName);
myGUI.setVisible(true); out.writeObject(m); out.flush();
} Object o = in.readObject();
public String getName() { return fName; } if(o instanceof MyException) throw (MyException) o;
boolean connect(InetAddress ina, int port) { m = (Message) o;
try { InitialData id = (InitialData) m.otherdata;
mySocket = new Socket(ina, port); String[] players = id.playerNames;
out = new ObjectOutputStream(mySocket.getOutputStream()); for(String player : players)
out.flush(); myGUI.addToList(player);
in = new ObjectInputStream(mySocket.getInputStream()); Posting[] posts = id.postings;
} catch (IOException io) { return false; } for(Posting p : posts) {
return true; myGUI.addPosting(p);
} Wrap byte level socket streams }
in object streams to allow transfer } catch(ClassNotFoundException cnfe) { }
of objects catch(ClassCastException cce) { }
catch(MyException me) { }
catch(IOException io) { }
}
Client Client
nabg nabg

public void run() { public void actionPerformed(ActionEvent e) {


runThread = Thread.currentThread(); String msg = myGUI.getInput();
try { if(msg == null) return;
for(;;) { try {
Message m = (Message) in.readObject(); Message m = new Message("Post", msg);
String s = m.operation; out.writeObject(m);
if(s.equals("Add_Client")) { out.flush();
String cname = (String) m.otherdata; out.reset();
myGUI.addToList(cname); } catch (IOException io) { }
} else if(s.equals("Remove_Client")) { }
String cname = (String) m.otherdata;
myGUI.removeFromList(cname);
} else if(s.equals("Post")){
Posting p = (Posting) m.otherdata;
myGUI.addPosting(p);
}
}
} catch (Exception e) { }
}

Client Client

nabg nabg

public void windowClosing(WindowEvent e) {


myGUI.setVisible(false);
runThread.stop();
Your programming of
try {
Message m = new Message("Quit", null);
Client - server systems
out.writeObject(m); Server (things that you should think about)
out.flush();
try { Thread.sleep(1000); } catch(InterruptedException ie) {} setting up listener mechanism, accepting new client and getting socket,
in.close(); creating thread for new client
out.close(); handle_client
} catch (IOException io) { }
System.out.println("Client terminated"); reading request;
System.exit(0); switch(keyword) into ...
} invoke separate functions for each of the commands that this
public void windowClosed(WindowEvent e) { } server handles

generation of response
how does it terminate?

Client

nabg nabg

Threaded server
Micro-IRC Server
All the one process (interacting clients)
Server
main thread handle_client shared
create socket
forever() data normal mechanism
read next request
bind to port if bye then break receptionist listening at published well know port
activate handle request accepts connections (getting new port-socket combination)
forever() send response handle_client

thread die
forever()
read next request
creates ClientHandler objects (and associated threads) for clients
accept client if bye then break

create new thread to


handle request
send response
thread die
shared data
handle_client
deal with this client forever() vector with ten most recent messages
read next request
start thread in if bye then break handle_client vector with ClientHandlers
handle_client handle request
forever()
read next request
send response if bye then break
thread die handle request
send response
thread die
nabg nabg

public class Server {


private static final int DEFAULT_PORT = 54321;
private static final int THREADPOOL_SIZE = 8;

Micro-IRC Server public static void main(String[] args) {


int port = DEFAULT_PORT;
Threaded-server, thread-
if(args.length==1) { pool style
try { port = Integer.parseInt(args[0]);
ClientHandlers } catch (NumberFormatException ne) { }
ServerSocket reception_socket = null;
hard code try {
wait for Register, check nickname (if name in use, return reception_socket = new ServerSocket(port);
exception, destroy this ClientHandler) }
catch(IOException ioe1) { }
register client with shared data SharedData sd = new SharedData();
send backlog info ExecutorService pool = Executors.newFixedThreadPool(
THREADPOOL_SIZE);
run main loop for(;;) {
read command try {
if Quit, terminate loop Socket client_socket = reception_socket.accept();
ClientHandler ch = new ClientHandler(client_socket, sd);
if Post, add message to shared data
pool.execute(ch);
? }
catch(Exception e) { }
on exit from main loop, or any i/o error, deregister this }
ClientHandler from shared data and terminate }
} Server

nabg nabg

public class SharedData {


private Vector<Posting> data;
Threads & Locking private Vector<ClientHandler> subscribers;

public SharedData() {
Multiple clients data = new Vector<Posting>();
subscribers = new Vector<ClientHandler>();
Multiple threads in server }
Possibly more than one thread trying to modify
shared data public synchronized void addClient(ClientHandler ch, String
nickname) throws MyException
Possibly more than one thread trying to use a {}
particular ClientHandler!
ClientHandlers own thread receiving a message public synchronized void removeClient(ClientHandler ch)
Some other thread trying to broadcast another users {}
posting
public synchronized void postMessage(String poster, String msg)
Need locks synchronized methods {}

}
SharedData

nabg nabg

public synchronized void addClient(ClientHandler ch, String nickname) throws public synchronized void removeClient(ClientHandler ch) {
MyException { subscribers.remove(ch);
for(ClientHandler c : subscribers) Message m = new Message("Remove_Client", ch.getName());
if(c.getName().equals(nickname)) for(ClientHandler c : subscribers)
throw new MyException("Duplicate name"); c.sendMessage(m);
// Send notification to each existing subscriber that there is a new participant }
Message m = new Message("Add_Client", nickname);
for(ClientHandler c: subscribers) public synchronized void postMessage(String poster, String msg) {
c.sendMessage(m); Posting p = new Posting(poster, msg);
// Add new client to collection data.add(p);
subscribers.add(ch); if(data.size()>10)
// Compose a response for new client data.removeElementAt(0);
String[] participants = new String[subscribers.size()]; Message m = new Message("Post", p);
int i=0; for(ClientHandler c: subscribers)
for(ClientHandler c: subscribers) c.sendMessage(m);
participants[i++] = c.getName(); }
Posting[] posts = data.toArray(new Posting[0]);
InitialData id = new InitialData(participants, posts);
Message reply = new Message("OK", id);
ch.sendMessage(reply);
} SharedData SharedData
nabg nabg

public class ClientHandler implements Runnable {


private ObjectInputStream input;
Locks on SharedData private ObjectOutputStream output;
private SharedData shared;
private Socket mySocket;
Synchronization locks on all methods
private String name;
Guarantee only one thread will be updating public ClientHandler(Socket aSocket,
shared data SharedData sd) throws IOException { }
public synchronized void sendMessage(
Message m) { }
public String getName() { return name; }
private boolean handleRegister() { }
public void run() { }
}

ClientHandler

nabg nabg

public ClientHandler(Socket aSocket, SharedData sd) throws IOException { private boolean handleRegister() {
mySocket = aSocket; try {
output = new ObjectOutputStream(aSocket.getOutputStream()); Message m = (Message) input.readObject();
output.flush(); String operation = m.operation;
input = new ObjectInputStream(aSocket.getInputStream()); if(!operation.equals("Register"))
shared = sd; Wrap byte level socket streams return false;
} name = (String) m.otherdata;
in object streams to allow transfer
shared.addClient(this, name);
of objects return true;
}
catch(ClassNotFoundException cnfe) { }
public synchronized void sendMessage(Message m) { catch(IOException ioe) { }
try { catch(MyException me) {
output.writeObject(m); try {
output.flush(); output.writeObject(me);
output.reset(); output.flush();
} }
catch(IOException ioe) { } catch(IOException io) {}
} }
return false;
ClientHandler } ClientHandler

nabg nabg

public void run() {


if(!handleRegister()) {
try { mySocket.close(); } catch(IOException ioe) {}

}
return; MicroIRC
for(;;) { As networked application, quite likely to get a break
try {
Message m = (Message) input.readObject(); in client-server link without formal logout
String operation = m.operation; client program died
if(operation.equals("Quit"))
break; server terminated
else
if(operation.equals("Post"))
...
shared.postMessage(name, (String) m.otherdata); No particular event sent to other process, but will get
}
catch(Exception e) { break; } fail at next read/write operation on socket.
}
Code tries to trap these and :
shared.removeClient(this); (if break spotted by client) terminate client process
try { mySocket.close(); } catch(IOException ioe) {}
} (if break spotted by server) destroy client handler object
ClientHandler

You might also like