IM269 Coursework 2: EchoClient.java
// IM269 - Coursework 2: Echo Client/Server
// Semester A, 2nd November 1998
// Eamonn Martin (BSc Computing)
// Student ID: 96/D59682
// efm001@unl.ac.uk
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
// Binary dialog window (yes/no, true/false, retry/cancel, etc)
class BinaryDialog extends Dialog {
private boolean response; // Dialog response flag
// Constructor - build the dialog window
public BinaryDialog(Frame parent, String title, String msg, String y, String n) {
super(parent, title, true);
TextArea m;
Button b;
Panel p;
p = new Panel(new BorderLayout()); // Message panel
p.add(m = new MessageArea(msg, TextArea.SCROLLBARS_NONE));
m.setBackground(Color.yellow); // Set message background
add(p); // Add message panel
p = new Panel(); // Button panel
ActionListener a = new ActionListener() { // Button handler
public void actionPerformed(ActionEvent e) {
response = (e.getActionCommand()=="1");
dispose(); // Close the dialog
}
};
p.add(b = new Button(y) { // Positive-response button
public String getActionCommand() { return "1"; }
});
b.addActionListener(a); // Set button handler
p.add(b = new Button(n) { // Negative-response button
public String getActionCommand() { return "0"; }
});
b.addActionListener(a); // Set button handler
add(p, "South"); // Add button panel
pack(); // Initialize layout
addWindowListener(new WindowAdapter() { // Enable window-closing
public void windowClosing(WindowEvent e) {
response = false; // Negative response
dispose(); // Close the dialog
}
});
}
// Prevent dialog resizing
public boolean isResizable() { return false; }
// Return the value of the response flag set by the dialog
public boolean getResponse() { return response; }
}
// Single-shot timed-delay object
class TimeOut extends Thread {
private boolean asleep; // Sleeping status flag
private long millis; // Sleep time
public TimeOut(long millis) { // Constructor
this.millis = millis; // Set sleep-time
}
public void start() { // Start the countdown
asleep = true; // Set asleep-flag
super.start(); // Start this thread
}
public void run() { // Start sleeping
try { sleep(millis); } // Suspend this thread
catch (InterruptedException e) {} // Ouch!
asleep = false; // Reset asleep-flag
}
public boolean isAsleep() { return asleep; } // Return asleep status
}
// EchoClient window
class ClientWindow extends AppWindow {
private TextArea text, echo; // Text input and echo
private TextField server, status; // Server and status message
private String host = "127.0.0.1"; // Default server host
private int port = 9999; // Default server port
// Constructor - build window with title and initial server
ClientWindow(String title, String srv) {
super(title);
Panel p, q;
Button b;
q = new Panel(new GridLayout(2, 1)); // Text I/O panel
p = new Panel(new BorderLayout()); // Input panel
p.add(new Label(" Input:"), "North"); // Input label
p.add(text = new TextArea()); // Input area
q.add(p); // Add to text panel
p = new Panel(new BorderLayout()); // Echo panel
p.add(new Label(" Response:"), "North");// Echo label
p.add(echo = new MessageArea()); // Echo area
q.add(p); // Add to text panel
add(q); // Add to window
q = new Panel(new GridLayout(2, 1)); // Top panel (server/buttons)
p = new Panel(new BorderLayout()); // Server panel
p.add(new Label(" Echo Server:"), "West");
p.add(server = new TextField(srv)); // Server field
server.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) { server.selectAll(); }
public void focusLost(FocusEvent e) { server.select(0, 0); }
});
server.setText(getServer()); // Set initial/default server
q.add(p); // Add to top panel
p = new Panel(new GridLayout()); // Button panel
b = new Button("Transmit"); // Transmit button
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { transmit(); }
});
p.add(b); // Add to button panel
b = new Button("Quit"); // Quit button
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { dispose(); }
});
p.add(b); // Add to button panel
q.add(p); // Add to top panel
add(q, "North"); // Add to window
p = new Panel(new BorderLayout()); // Status panel
p.add(status = new MessageField()); // Status message
add(p, "South"); // Add to window
host = getHost(); // Update default host
port = getPort(); // Update default port
text.setText("Send me!"); // Default text for convenience
setBackground(SystemColor.control); // Set background colour
setSize(350, 250); // Set window size
setVisible(true); // Display the window
}
// Wait a specified time for a character from an input stream
private int readWait(long millis, InputStream i) {
TimeOut t = new TimeOut(millis); // Timed-delay object
t.start(); // Start the timer
try { while (i.available() < 1) // Wait for a character
if (!t.isAsleep()) return -1; // Timout occurred?
t.stop(); // Stop the timer
return i.read(); // Return the character
} catch (IOException e) {}
return -1; // I/O error - fail
}
// Display a retry/cancel dialog and return the response
private boolean retryDialog() {
int w = 250, h = 200; // Dialog dimensions
BinaryDialog d; // Binary dialog window
d = new BinaryDialog(this, "EchoClient: " + getServer(),
"\nThis server is not responding!\n\nClick 'Retry' to " +
"continue waiting for a response from the server.\n\n" +
"Click 'Cancel' to abort this transaction.", " Retry ", "Cancel");
Dimension s = getToolkit().getScreenSize();
d.setBounds(s.width/2 - w/2, s.height/2 - h/2, w, h);
d.setVisible(true); // Display the dialog
return d.getResponse(); // User's response
}
// Write string to output stream and read back from input stream
private String echoString(String s, Socket socket) {
DataInputStream in = null;
DataOutputStream out = null;
try { // Write/read string
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
String buf = ""; // String buffer
out.writeBytes(s); // Write string
for (int c, i=s.length(); i > 0; --i) {
do { // Loop until all echoed
c = readWait(10000, in); // Wait 10-secs
if (c < 0) if (!retryDialog()) // No echo?
throw new IOException();// Give up
} while (c < 0); // Continue waiting?
buf += (char)c; // Append character to buffer
}
echo.setText(s = buf); // Set echo text
} catch (IOException e) { // Operation failed
s = null;
} finally { // Close i/o streams
try { if (out!=null) out.close(); }
catch (IOException e) { s = null; }
try { if (in!=null) in.close(); }
catch (IOException e) { s = null; }
}
return s;
}
// Transmit text to echo-server
private void transmit() {
String s;
Socket socket;
echo.setText(""); // Clear current echo text
server.setText(getServer()); // Set current host:port
report("Contacting server..."); // Begin echo transaction
try { // Create the client socket
socket = new Socket(getHost(), getPort());
} catch (IOException e) { // No socket
report("Unable to contact server!");
return; // Abort
}
report("Transmitting..."); // Transmit/receive text
if ((s = echoString(text.getText(), socket))!=null) echo.setText(s);
report((s!=null) ? "Transaction complete." : "EchoClient I/O error!");
try { socket.close(); } catch (IOException e) {}
}
// Return current host (specified or default)
private String getHost() {
String s = server.getText(); // Get text in server field
int i = s.indexOf(':'); // Locate port specifier
if (i>=0) s = s.substring(0, i); // Remove port specification
return (s.length() > 0) ? s : host; // Specified or default host
}
// Return current port (specified or default)
private int getPort() {
String s = server.getText(); // Get text in server field
int i = s.indexOf(':'); // Locate port specifier
if ((i>=0) && (s.length() > i+1)) try { // Read port number?
return (Integer.decode(s.substring(i+1))).intValue();
} catch (NumberFormatException e) {} // Invalid port number
return port; // Default port
}
// Return the complete host:port string for the server
private String getServer() { return getHost() + ":" + getPort(); }
// Write a string to the status message area
void report(String s) { status.setText(s); }
}
// Create the client window
public class EchoClient {
private static String info =
"\nIM269 - Coursework 2: EchoClient\nSemester A, 2nd November 1998\n" +
"Eamonn Martin (BSc Computing)\nStudent ID: 96/D59682\nefm001@unl.ac.uk\n\n" +
"EchoClient [host][:port]\n\n" +
"The default address used for the echo-server is 127.0.0.1:9999 (loopback).\n" +
"A different default host and/or port may be specified on the command-line.\n" +
"The current server may be changed by modifying the 'Echo Server' field.\n\n" +
"A full listing of this program can be found on the World Wide Web at:\n\n" +
"\t\t http://www2.unl.ac.uk/~efm001/im269/\n\n" +
"Starting EchoClient...";
// Print info and create client window
public static void main(String[] args) {
System.out.println(info);
String srv = (args.length > 0) ? args[0] : "";
new ClientWindow("EchoClient", srv).report("EchoClient Ready");
}
}
Go To: IM269: Programming The Internet