IM269 Coursework 2: EchoServer.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.*;

// EchoServer window
class ServerWindow extends AppWindow {
	private TextArea log;

	// Constructor
	ServerWindow(String title) {
		super(title);
		Button b;
		Panel p;

		p = new Panel(new BorderLayout());	// Server log
		p.add(new Label("Transaction Log:"), "North");
		p.add(log = new MessageArea());
		add(p);

		p = new Panel(new GridLayout());	// Button panel
		b = new Button("Reset");		// Reset button
		b.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) { resetServer(); }
		});
		p.add(b);
		b = new Button("Quit");			// Quit button
		b.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) { dispose(); }
		});
		p.add(b);
		add(p, "South");
		setBackground(SystemColor.control);	// Set background colour
		setSize(350, 250);			// Set window size
		setVisible(true);			// Display the window
		resetServer();				// Initialize the server
	}

	// Reset the server
	private void resetServer() {
		log.setText("");			// Empty transaction log
		EchoServer.num = 0;			// Reset transaction number
		println("EchoServer Transaction Log");
		println(new java.util.Date().toString());
		println("EchoServer listening on port " + EchoServer.port + "...");
	}

	// Write a string to the transaction log area
	void println(String s) { log.append(s + "\n"); }

	// Close the server socket
	public void windowClosed(WindowEvent e) { 
		try {	// Close the server socket (if open)
			if (EchoServer.socket!=null) EchoServer.socket.close();
		} catch (IOException x) {		// Whatever...
		} finally { super.windowClosed(e); }	// Terminate Java system
	}
}

// Client transactions
class Transaction extends Thread {
	private Socket socket;				// Client socket
	private String id;				// Transaction ID string

	// Constructor
	Transaction(int id, Socket socket) {
		this.socket = socket;			// Set client socket
		this.id = "#" + id + ": ";		// Set transaction ID
		start();				// Start transaction thread
	}

	// Echo string from socket input stream to socket output stream
	// Incoming data is echoed byte-by-byte without buffering
	// End of data is indicated by the end of the input stream (not a newline)
	// Thus avoids readLine() (noted in TYJ - pp181) and allows multi-line text
	private String echoString(Socket socket) {
		DataInputStream in = null;		// Input stream
		DataOutputStream out = null;		// Output stream
		String s = "";				// String buffer
		try {					// Read/write string
			in = new DataInputStream(socket.getInputStream());
			out = new DataOutputStream(socket.getOutputStream());
			for (int c; (c = in.read())!=-1; out.write(c)) s += (char)c;
		} 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;				// Echoed-string or null
	}

	// Execute transaction and report progress
	public void run() {
		String s;
		println(new java.util.Date().toString());
		println("Remote IP: " + socket.getInetAddress());
		println("Remote Port: " + socket.getPort());
		if ((s = echoString(socket))!=null) println("Text Received:\n" + s);
		println((s!=null) ? "Transaction complete." : "EchoServer I/O error!");
		try { socket.close(); } catch (IOException e) {}
	}

	// Report a message prefixed with the transaction ID number
	private void println(String s) { EchoServer.win.println(id + s); }
}

// Create the server socket and the window and process transactions
public class EchoServer {
	static ServerWindow win;			// GUI object
	static ServerSocket socket;			// Server socket object
	static int port = 9999, num;			// Port and transaction number
	private static String info =
	    "\nIM269 - Coursework 2: EchoServer\nSemester A, 2nd November 1998\n" +
	    "Eamonn Martin (BSc Computing)\nStudent ID: 96/D59682\nefm001@unl.ac.uk\n\n" +
	    "EchoServer [port]\n\n" +
	    "The optional 'port' command-line parameter overrides the default of 9999.\n" +
	    "The 'Reset' button clears the log and resets the transaction counter.\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";


	// Create the GUI and the server socket and monitor for clients
	public static void main(String[] args) {
		System.out.println(info);
		if (args.length > 0) try {		// Read command-line port?
			port = (Integer.decode(args[0])).intValue();
		} catch (NumberFormatException e) {	// Invalid port number
			System.err.println(args[0]+" is not a valid port number!");
			return;				// Abort program
		}
		try { socket = new ServerSocket(port); }// Create a server socket
		catch (IOException e) {			// No socket created
			System.err.println("Unable to create socket on port "+port+"!");
			return;				// Abort program
		}
		System.out.println("Starting EchoServer...");
		win = new ServerWindow("EchoServer");	// Create server window
		while (true) {				// Wait for connections
			try {	Socket s = socket.accept();
				win.println("\nConnection #" + (++num) + " accepted.");
				new Transaction(num, s);// Create a transaction
			} catch (IOException e) {}
		}
	}
}

Go To: IM269: Programming The Internet