diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..739346c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+/bin
diff --git a/.project b/.project
new file mode 100644
index 0000000..8f0f214
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ ex22-square
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/src/square/SquareClient.java b/src/square/SquareClient.java
new file mode 100644
index 0000000..9cb15a3
--- /dev/null
+++ b/src/square/SquareClient.java
@@ -0,0 +1,98 @@
+package square;
+
+import java.io.*;
+import java.net.Socket;
+
+/**
+ * SquareClient is a client that sends requests to the SquareServer
+ * and interprets its replies.
+ * A new SquareClient is "open" until the close() method is called,
+ * at which point it is "closed" and may not be used further.
+ */
+public class SquareClient {
+ private Socket socket;
+ private BufferedReader in;
+ private PrintWriter out;
+ // Rep invariant: socket, in, out != null
+
+ /**
+ * Make a SquareClient and connect it to a server running on
+ * hostname at the specified port.
+ * @throws IOException if can't connect
+ */
+ public SquareClient(String hostname, int port) throws IOException {
+ socket = new Socket(hostname, port);
+ in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+ }
+
+ /**
+ * Send a request to the server. Requires this is "open".
+ * @param x number to square
+ * @throws IOException if network or server failure
+ */
+ public void sendRequest(int x) throws IOException {
+ out.print(x + "\n");
+ out.flush(); // important! make sure x actually gets sent
+ }
+
+ /**
+ * Get a reply from the next request that was submitted.
+ * Requires this is "open".
+ * @return square of requested number
+ * @throws IOException if network or server failure
+ */
+ public int getReply() throws IOException {
+ String reply = in.readLine();
+ if (reply == null) {
+ throw new IOException("connection terminated unexpectedly");
+ }
+
+ try {
+ return Integer.valueOf(reply);
+ } catch (NumberFormatException nfe) {
+ throw new IOException("misformatted reply: " + reply);
+ }
+ }
+
+ /**
+ * Closes the client's connection to the server.
+ * This client is now "closed". Requires this is "open".
+ * @throws IOException if close fails
+ */
+ public void close() throws IOException {
+ in.close();
+ out.close();
+ socket.close();
+ }
+
+
+
+
+ private static final int N = 100;
+
+ /**
+ * Use a SquareServer to square all the integers from 1 to N.
+ */
+ public static void main(String[] args) {
+ try {
+ SquareClient client = new SquareClient("localhost", SquareServer.SQUARE_PORT);
+
+ // send the requests to square 1...N
+ for (int x = 1; x <= N; ++x) {
+ client.sendRequest(x);
+ System.out.println(x + "^2 = ?");
+ }
+
+ // collect the replies
+ for (int x = 1; x <= N; ++x) {
+ int y = client.getReply();
+ System.out.println(x + "^2 = " + y);
+ }
+
+ client.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+}
diff --git a/src/square/SquareQueue.java b/src/square/SquareQueue.java
new file mode 100644
index 0000000..e177289
--- /dev/null
+++ b/src/square/SquareQueue.java
@@ -0,0 +1,97 @@
+package square;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Squares integers.
+ */
+class Squarer {
+
+ private final BlockingQueue in;
+ private final BlockingQueue out;
+ // Rep invariant: in, out != null
+
+ /**
+ * Make a squarer that will listen for requests and generate replies.
+ * @param requests queue to receive requests from
+ * @param replies queue to send replies to
+ */
+ public Squarer(BlockingQueue requests, BlockingQueue replies) {
+ this.in = requests;
+ this.out = replies;
+ }
+
+ /**
+ * Start handling squaring requests.
+ */
+ public void start() {
+ new Thread(new Runnable() {
+ public void run() {
+ while (true) {
+ // TODO: we may want a way to stop the thread
+ try {
+ // block until a request arrives
+ int x = in.take();
+ // compute the answer and send it back
+ int y = x * x;
+ out.put(new SquareResult(x, y));
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+ }
+ }).start();
+ }
+}
+
+/**
+ * An immutable squaring result message.
+ */
+class SquareResult {
+ private final int input;
+ private final int output;
+
+ /**
+ * Make a new result message.
+ * @param input input number
+ * @param output square of input
+ */
+ public SquareResult(int input, int output) {
+ this.input = input;
+ this.output = output;
+ }
+
+ // TODO: we will want more observers, but for now...
+
+ @Override public String toString() {
+ return input + "^2 = " + output;
+ }
+}
+
+public class SquareQueue {
+
+ /**
+ * Create and use a squarer.
+ */
+ public static void main(String[] args) {
+
+ BlockingQueue requests = new LinkedBlockingQueue<>();
+ BlockingQueue replies = new LinkedBlockingQueue<>();
+
+ Squarer squarer = new Squarer(requests, replies);
+ squarer.start();
+
+ try {
+ // make a request
+ requests.put(42);
+
+ // maybe do something concurrently...
+
+ // read the reply
+ System.out.println(replies.take());
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+}
diff --git a/src/square/SquareServer.java b/src/square/SquareServer.java
new file mode 100644
index 0000000..d627039
--- /dev/null
+++ b/src/square/SquareServer.java
@@ -0,0 +1,104 @@
+package square;
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * SquareServer is a server that squares integers passed to it.
+ * It accepts requests of the form:
+ * Request ::= Number "\n"
+ * Number ::= [0-9]+
+ * and for each request, returns a reply of the form:
+ * Reply ::= (Number | "err") "\n"
+ * where a Number is the square of the request number,
+ * or "err" is used to indicate a misformatted request.
+ * SquareServer can handle only one client at a time.
+ */
+public class SquareServer {
+ /** Default port number where the server listens for connections. */
+ public static final int SQUARE_PORT = 4949;
+
+ private ServerSocket serverSocket;
+ // Rep invariant: serverSocket != null
+
+ /**
+ * Make a SquareServer that listens for connections on port.
+ * @param port port number, requires 0 <= port <= 65535
+ */
+ public SquareServer(int port) throws IOException {
+ serverSocket = new ServerSocket(port);
+ }
+
+ /**
+ * Run the server, listening for connections and handling them.
+ * @throws IOException if the main server socket is broken
+ */
+ public void serve() throws IOException {
+ while (true) {
+ // block until a client connects
+ Socket socket = serverSocket.accept();
+ try {
+ handle(socket);
+ } catch (IOException ioe) {
+ ioe.printStackTrace(); // but don't terminate serve()
+ } finally {
+ socket.close();
+ }
+ }
+ }
+
+ /**
+ * Handle one client connection. Returns when client disconnects.
+ * @param socket socket where client is connected
+ * @throws IOException if connection encounters an error
+ */
+ private void handle(Socket socket) throws IOException {
+ System.err.println("client connected");
+
+ // get the socket's input stream, and wrap converters around it
+ // that convert it from a byte stream to a character stream,
+ // and that buffer it so that we can read a line at a time
+ BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+ // similarly, wrap character=>bytestream converter around the
+ // socket output stream, and wrap a PrintWriter around that so
+ // that we have more convenient ways to write Java primitive
+ // types to it.
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+
+ try {
+ // each request is a single line containing a number
+ for (String line = in.readLine(); line != null; line = in.readLine()) {
+ System.err.println("request: " + line);
+ try {
+ int x = Integer.valueOf(line);
+ // compute answer and send back to client
+ int y = x * x;
+ System.err.println("reply: " + y);
+ out.print(y + "\n");
+ } catch (NumberFormatException e) {
+ // complain about ill-formatted request
+ System.err.println("reply: err");
+ out.println("err");
+ }
+ // important! flush our buffer so the reply is sent
+ out.flush();
+ }
+ } finally {
+ out.close();
+ in.close();
+ }
+ }
+
+ /**
+ * Start a SquareServer running on the default port.
+ */
+ public static void main(String[] args) {
+ try {
+ SquareServer server = new SquareServer(SQUARE_PORT);
+ server.serve();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/square/SquareServerMulti.java b/src/square/SquareServerMulti.java
new file mode 100644
index 0000000..119e6c3
--- /dev/null
+++ b/src/square/SquareServerMulti.java
@@ -0,0 +1,123 @@
+package square;
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * SquareServerMulti is a server that squares integers passed to it.
+ * It accepts requests of the form:
+ * Request ::= Number "\n"
+ * Number ::= [0-9]+
+ * and for each request, returns a reply of the form:
+ * Reply ::= (Number | "err") "\n"
+ * where a Number is the square of the request number,
+ * or "err" is used to indicate a misformatted request.
+ * SquareServerMulti can handle multiple concurrent clients.
+ */
+public class SquareServerMulti {
+ /** Default port number where the server listens for connections. */
+ public static final int SQUARE_PORT = 4949;
+
+ private ServerSocket serverSocket;
+ // Rep invariant: serverSocket != null
+ //
+ // Thread safety argument:
+ // TODO SQUARE_PORT
+ // TODO serverSocket
+ // TODO socket objects
+ // TODO readers and writers in handle()
+ // TODO data in handle()
+
+ /**
+ * Make a SquareServerMulti that listens for connections on port.
+ * @param port port number, requires 0 <= port <= 65535
+ */
+ public SquareServerMulti(int port) throws IOException {
+ serverSocket = new ServerSocket(port);
+ }
+
+ /**
+ * Run the server, listening for connections and handling them.
+ * @throws IOException if the main server socket is broken
+ */
+ public void serve() throws IOException {
+ while (true) {
+ // block until a client connects
+ final Socket socket = serverSocket.accept();
+ // create a new thread to handle that client
+ Thread handler = new Thread(new Runnable() {
+ public void run() {
+ try {
+ try {
+ handle(socket);
+ } finally {
+ socket.close();
+ }
+ } catch (IOException ioe) {
+ // this exception wouldn't terminate serve(),
+ // since we're now on a different thread, but
+ // we still need to handle it
+ ioe.printStackTrace();
+ }
+ }
+ });
+ // start the thread
+ handler.start();
+ }
+ }
+
+ /**
+ * Handle one client connection. Returns when client disconnects.
+ * @param socket socket where client is connected
+ * @throws IOException if connection encounters an error
+ */
+ private void handle(Socket socket) throws IOException {
+ System.err.println("client connected");
+
+ // get the socket's input stream, and wrap converters around it
+ // that convert it from a byte stream to a character stream,
+ // and that buffer it so that we can read a line at a time
+ BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+ // similarly, wrap character=>bytestream converter around the
+ // socket output stream, and wrap a PrintWriter around that so
+ // that we have more convenient ways to write Java primitive
+ // types to it.
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
+
+ try {
+ // each request is a single line containing a number
+ for (String line = in.readLine(); line != null; line = in.readLine()) {
+ System.err.println("request: " + line);
+ try {
+ int x = Integer.valueOf(line);
+ // compute answer and send back to client
+ int y = x * x;
+ System.err.println("reply: " + y);
+ out.println(y);
+ } catch (NumberFormatException e) {
+ // complain about ill-formatted request
+ System.err.println("reply: err");
+ out.print("err\n");
+ }
+ // important! our PrintWriter is auto-flushing, but if it were not:
+ // out.flush();
+ }
+ } finally {
+ out.close();
+ in.close();
+ }
+ }
+
+ /**
+ * Start a SquareServerMulti running on the default port.
+ */
+ public static void main(String[] args) {
+ try {
+ SquareServerMulti server = new SquareServerMulti(SQUARE_PORT);
+ server.serve();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}